C++ 如何从 boost::shared_ptr 释放指针?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1525764/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 20:17:32  来源:igfitidea点击:

How to release pointer from boost::shared_ptr?

c++boostshared-ptr

提问by user152508

Can boost::shared_ptr release the stored pointer without deleting it?

boost::shared_ptr 可以释放存储的指针而不删除它吗?

I can see no release function exists in the documentation, also in the FAQ is explained why it does not provide release function, something like that the release can not be done on pointers that are not unique. My pointers are unique. How can I release my pointers ? Or which boost smart pointer class to use that will allow me releasing of the pointer ? I hope that you won't say use auto_ptr :)

我可以看到文档中不存在发布功能,在常见问题解答中也解释了为什么它不提供发布功能,例如无法在非唯一指针上进行发布。我的指针是独一无二的。我怎样才能释放我的指针?或者使用哪个 boost 智能指针类可以让我释放指针?我希望你不会说使用 auto_ptr :)

采纳答案by Martin Ba

You need to use a deleter that you can request not to delete the underlying pointer.

您需要使用可以请求不删除底层指针的删除器。

See this answer(which has been marked as a duplicate of this question) for more information.

有关更多信息,请参阅此答案(已标记为此问题的副本)。

回答by sellibitze

Don't. Boost's FAQ entry:

别。Boost 的 FAQ 条目:

Q. Why doesn't shared_ptr provide a release() function?

A. shared_ptrcannot give away ownership unless it's unique() because the other copy will still destroy the object.

Consider:

shared_ptr<int> a(new int);
shared_ptr<int> b(a); // a.use_count() == b.use_count() == 2

int * p = a.release();

// Who owns p now? b will still call delete on it in its destructor.

Furthermore, the pointer returned by release() would be difficult to deallocate reliably, as the source shared_ptr could have been created with a custom deleter.

。为什么 shared_ptr 不提供 release() 函数?

一个shared_ptr不能放弃所有权,除非它是 unique() 因为另一个副本仍然会破坏对象。

考虑:

shared_ptr<int> a(new int);
shared_ptr<int> b(a); // a.use_count() == b.use_count() == 2

int * p = a.release();

// Who owns p now? b will still call delete on it in its destructor.

此外,release() 返回的指针将难以可靠地解除分配,因为源 shared_ptr 可能已使用自定义删除器创建。

So, this would be safe in case it's the only shared_ptr instance pointing to your object (when unique() returns true) and the object doesn't require a special deleter. I'd still question your design, if you used such a .release() function.

因此,这将是安全的,以防它是唯一指向您的对象的 shared_ptr 实例(当 unique() 返回 true 时)并且该对象不需要特殊的删除器。如果您使用了这样的 .release() 函数,我仍然会质疑您的设计。

回答by Kirill V. Lyadvinsky

You could use fake deleter. Then pointers will not be deleted actually.

你可以使用假删除器。那么指针实际上不会被删除。

struct NullDeleter {template<typename T> void operator()(T*) {} };

// pp of type some_t defined somewhere
boost::shared_ptr<some_t> x(pp, NullDeleter() );

回答by curiousguy

Kids, don't do this at home:

孩子们,不要在家里这样做:

// set smarty to point to nothing
// returns old(smarty.get())
// caller is responsible for the returned pointer (careful)
template <typename T>
T* release (shared_ptr<T>& smarty) {
    // sanity check:
    assert (smarty.unique());
    // only one owner (please don't play games with weak_ptr in another thread)
    // would want to check the total count (shared+weak) here

    // save the pointer:
    T *raw = &*smarty;
    // at this point smarty owns raw, can't return it

    try {
        // an exception here would be quite unpleasant

        // now smash smarty:
        new (&smarty) shared_ptr<T> ();
        // REALLY: don't do it!
        // the behaviour is not defined!
        // in practice: at least a memory leak!
    } catch (...) {
        // there is no shared_ptr<T> in smarty zombie now
        // can't fix it at this point:
        // the only fix would be to retry, and it would probably throw again
        // sorry, can't do anything
        abort ();
    }
    // smarty is a fresh shared_ptr<T> that doesn't own raw

    // at this point, nobody owns raw, can return it
    return raw;
}

Now, is there a way to check if total count of owners for the ref count is > 1?

现在,有没有办法检查引用计数的所有者总数是否大于 1?

回答by Timbo

To let the pointer point to nothing again, you can call shared_ptr::reset().

要让指针再次指向空,您可以调用shared_ptr::reset().

However, this will delete the object pointed to when your pointer is the last reference to the object. This, however, is exactly the desired behaviour of the smart pointer in the first place.

但是,当您的指针是对对象的最后一个引用时,这将删除指向的对象。然而,这正是智能指针所期望的行为。

If you just want a reference that does not hold the object alive, you can create a boost::weak_ptr(see boost documentation). A weak_ptrholds a reference to the object but does not add to the reference count, so the object gets deleted when only weak references exist.

如果您只想要一个不保持对象处于活动状态的引用,您可以创建一个boost::weak_ptr(请参阅boost 文档)。Aweak_ptr持有对对象的引用,但不会增加引用计数,因此当仅存在弱引用时,对象会被删除。

回答by Andreas Spindler

The basis of sharing is trust. If some instance in your program needs to release the raw pointer, it is almost for sure that shared_ptris the wrong type.

共享的基础是信任。如果程序中的某个实例需要释放原始指针,几乎可以肯定这shared_ptr是错误的类型。

However, recently I wanted to do this too, as I needed to deallocate from a different process-heap. In the end I was taught that my older decision to use some std::shared_ptrwas not thought-out.

但是,最近我也想这样做,因为我需要从不同的进程堆中释放。最后我被告知,我之前使用一些的决定std::shared_ptr并没有经过深思熟虑。

I just routinely used this type for cleanup. But the pointer was just duplicated on a few places. Actually I needed a std::unique_ptr, which (suprise) has a releasefunction.

我只是经常使用这种类型进行清理。但是指针只是在几个地方重复了。实际上我需要一个std::unique_ptr,它(惊喜)有一个release功能。

回答by Alexander Drichel

Forgive them for they know not what they do. This example works with boost::shared_ptr and msvs std::shared_ptr without memory leaks!

原谅他们,因为他们不知道自己在做什么。这个例子适用于 boost::shared_ptr 和 msvs std::shared_ptr ,没有内存泄漏!

template <template <typename> class TSharedPtr, typename Type>
Type * release_shared(TSharedPtr<Type> & ptr)
{
    //! this struct mimics the data of std:shared_ptr ( or boost::shared_ptr )
    struct SharedVoidPtr
    {
        struct RefCounter
        {
            long _Uses;
            long _Weaks;
        };

        void * ptr;
        RefCounter * refC;

        SharedVoidPtr()
        {
            ptr = refC = nullptr;
        }

        ~SharedVoidPtr()
        {
            delete refC;
        }
    };

    assert( ptr.unique() );

    Type * t = ptr.get();

    SharedVoidPtr sp; // create dummy shared_ptr
    TSharedPtr<Type> * spPtr = (TSharedPtr<Type>*)( &sp );
    spPtr->swap(ptr); // swap the contents

    ptr.reset();
    // now the xxx::shared_ptr is empy and
    // SharedVoidPtr releases the raw poiter but deletes the underlying counter data
    return t;
}

回答by David Thornley

You can delete the shared pointer, which seems much the same to me. If pointers are always unique, then std::auto_ptr<>is a good choice. Bear in mind that unique pointers can't be used in STL containers, since operations on them do a lot of copying and temporary duplication.

您可以删除共享指针,这对我来说似乎很相似。如果指针总是唯一的,那么std::auto_ptr<>是一个不错的选择。请记住,在 STL 容器中不能使用唯一指针,因为对它们的操作会进行大量复制和临时复制。

回答by Aberrant

I'm not entirely sure if your question is about achieving this, but if you want behaviour from a shared_ptr, where, if you release the value from one shared_ptr, all the other shared pointers to the same value become a nullptr, then you can put a unique_ptrin a shared_ptrto achieve that behaviour.

我不完全确定您的问题是否与实现这一点有关,但是如果您想要 a 的行为shared_ptr,如果您从 one 释放值shared_ptr,则指向同一值的所有其他共享指针将变为 nullptr,那么您可以放置​​一个unique_ptrshared_ptr实现这一行为。

void print(std::string name, std::shared_ptr<std::unique_ptr<int>>& ptr)
{
    if(ptr == nullptr || *ptr == nullptr)
    {
        std::cout << name << " points to nullptr" << std::endl;
    }
    else
    {
        std::cout << name << " points to value " << *(*ptr) << std::endl;
    }
}

int main()
{
    std::shared_ptr<std::unique_ptr<int>> original;
    original = std::make_shared<std::unique_ptr<int>>(std::make_unique<int>(50));

    std::shared_ptr<std::unique_ptr<int>> shared_original = original;

    std::shared_ptr<std::unique_ptr<int>> thief = nullptr;

    print(std::string("original"), original);
    print(std::string("shared_original"), shared_original);
    print(std::string("thief"), thief);

    thief = std::make_shared<std::unique_ptr<int>>(original->release());

    print(std::string("original"), original);
    print(std::string("shared_original"), shared_original);
    print(std::string("thief"), thief);

    return 0;
}

Output:

输出:

original points to value 50
shared_original points to value 50
thief points to nullptr
original points to nullptr
shared_original points to nullptr
thief points to value 50

This behaviour allows you to share a resource (like an array), then later reuse that resource while invalidating all the shared references to this resource.

此行为允许您共享资源(如数组),然后在使对该资源的所有共享引用无效的同时重用该资源。

回答by steve

I am using Poco::HTTPRequestHandlerFactory which expects to return a raw HTTPRequestHandler*, the Poco framework deletes the handler once the request finishes.

我正在使用 Poco::HTTPRequestHandlerFactory,它期望返回一个原始的 HTTPRequestHandler*,一旦请求完成,Poco 框架就会删除处理程序。

Also using DI Sauce project to create the controllers, however the Injector returns shared_ptr which I cannot return directly, and returning handler.get() is no good either since the as soon as this function returns the shared_ptr goes out of scope and deletes then handler before its executed, so here is a reasonable (I think) reason to have a .release() method. I ended up creating a HTTPRequestHandlerWrapper class as follows :-

同样使用 DI Sauce 项目来创建控制器,但是注入器返回 shared_ptr ,我不能直接返回,并且返回 handler.get() 也不好,因为一旦此函数返回 shared_ptr 超出范围并删除然后处理程序在它执行之前,所以这是一个合理的(我认为)使用 .release() 方法的理由。我最终创建了一个 HTTPRequestHandlerWrapper 类,如下所示:-

class HTTPRequestHandlerWrapper : public HTTPRequestHandler {
private:
    sauce::shared_ptr<HTTPRequestHandler> _handler;

public:
    HTTPRequestHandlerWrapper(sauce::shared_ptr<HTTPRequestHandler> handler) {
        _handler = handler;
    }

    virtual void handleRequest(HTTPServerRequest& request, HTTPServerResponse& response) {
        return _handler->handleRequest(request, response);
    }
};

and then the factory would

然后工厂会

HTTPRequestHandler* HttpHandlerFactory::createRequestHandler(const HTTPServerRequest& request) {
    URI uri = URI(request.getURI());
    auto path = uri.getPath();
    auto method = request.getMethod();

    sauce::shared_ptr<HTTPRequestHandler> handler = _injector->get<HTTPRequestHandler>(method + ":" + path);

    return new HTTPRequestHandlerWrapper(handler);
}

which satisfied both Sauce and Poco and works nicely.

这让 Sauce 和 Poco 都满意,而且效果很好。