40

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

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

4

14 回答 14

31

不。Boost 的常见问题解答条目:

。为什么 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 可能是使用自定义删除器创建的。

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

于 2009-10-06T15:45:16.207 回答
24

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

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

// pp of type some_t defined somewhere
boost::shared_ptr<some_t> x(pp, NullDeleter() );
于 2009-10-06T14:56:52.450 回答
7

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

// 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;
}

现在,有没有办法检查 ref 计数的所有者总数是否 > 1?

于 2011-10-08T22:39:20.270 回答
6

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

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

于 2013-05-19T11:15:04.197 回答
4

要让指针再次指向任何内容,您可以调用shared_ptr::reset().

但是,当您的指针是对该对象的最后引用时,这将删除指向的对象。然而,这正是智能指针首先需要的行为。

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

于 2009-10-06T14:28:35.960 回答
3

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

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

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

于 2012-09-11T14:57:28.770 回答
2

原谅他们,因为他们不知道自己在做什么。这个例子适用于 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;
}
于 2012-12-04T11:23:20.180 回答
1

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

于 2009-10-06T14:24:16.213 回答
1

我不完全确定您的问题是否与实现这一点有关,但是如果您想要来自 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;
}

输出:

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

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

于 2017-08-04T15:21:07.760 回答
0

这是一个可能有用的hack。除非您处于真正的束缚中,否则我不会推荐它。

template<typename T>
T * release_shared(std::shared_ptr<T> & shared)
{
    static std::vector<std::shared_ptr<T> > graveyard;
    graveyard.push_back(shared);
    shared.reset();
    return graveyard.back().get();
}
于 2011-09-29T22:31:01.697 回答
0

如果您的指针确实是唯一的,请使用std::unique_ptr或者boost::scoped_ptr前者不适用于您的编译器。否则考虑结合使用boost::shared_ptrwith boost::weak_ptr。查看Boost 文档了解详细信息。

于 2013-05-19T10:34:24.867 回答
0

我需要通过异步处理程序传递一个指针,并在失败的情况下保持自毁行为,但最终的 API 需要一个原始指针,所以我让这个函数从单个 shared_ptr 中释放:

#include <memory>

template<typename T>
T * release(std::shared_ptr<T> & ptr)
{
    struct { void operator()(T *) {} } NoDelete;
    
    T * t = nullptr;
    if (ptr.use_count() == 1)
    {
        t = ptr.get();
        ptr.template reset<T>(nullptr, NoDelete);
    }
    return t;
}

如果ptr.use_count() != 1你应该得到一个nullptr


请注意,来自cppreference(我的粗体强调):

如果use_count返回 1,则没有其他所有者。unique()(为此用例提供了不推荐使用的成员函数。)在多线程环境中,这并不意味着对象可以安全修改,因为以前的共享所有者对托管对象的访问可能尚未完成,并且因为新的共享所有者可能同时引入,如 by std::weak_ptr::lock

于 2017-04-14T12:37:47.917 回答
0

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

也使用 DI Sauce 项目创建控制器,但是 Injector 返回 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);
    }
};

然后工厂会

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);
}

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

于 2017-03-28T00:50:42.643 回答
-1

简单的解决方案,增加引用然后泄漏shared_pointer。

boost::shared_ptr<MyType> shared_pointer_to_instance(new MyType());
new boost::shared_ptr<MyType>();
MyType * raw_pointer = shared_pointer_to_instance.get()

这显然会导致 shared_ptr 和 MyType * 的内存泄漏

于 2016-03-07T10:30:48.883 回答