显式删除shared_ptr

Explicitly deleting a shared_ptr

本文关键字:ptr shared 删除      更新时间:2023-10-16

这里有一个简单的问题:是否允许您自己显式删除boost::shared_ptr?你应该吗?

澄清一下,我的意思不是删除shared_ptr持有的指针。我指的是真正的shared_ptr本身。我知道大多数人建议不要这样做,所以我只是想知道明确地这样做是否可以。

您的问题不清楚。如果你已经动态地分配了一个shared_ptr,那么你当然可以随时delete

但是,如果你问是否允许删除shared_ptr管理的任何对象,那么答案是。。。这取决于情况。如果shared_ptr::unique返回true,则调用shared_ptr::reset将删除托管对象。但是,如果shared_ptr::unique返回false,则表示有多个shared_ptr共享该对象的所有权。在这种情况下,对reset的调用只会导致引用计数减少1,当管理该对象的最后一个shared_ptr超出范围或本身是reset时,将发生对象的实际删除。

编辑:
编辑后,您似乎在询问删除动态分配的shared_ptr。类似这样的东西:

auto sp = new boost::shared_ptr<int>( new int(42) );
// do something with sp
delete sp;

这是允许的,并且将按预期工作,尽管这将是一个不寻常的用例。唯一需要注意的是,如果在分配和删除sp之间创建了另一个共享对象所有权的shared_ptr,则删除sp不会导致删除该对象,只有当对象的引用计数为0时才会发生这种情况。

[编辑:如果并且仅当它是用new创建的,则可以用delete创建shared_ptr,与任何其他类型一样。我想不出为什么要用new创建shared_ptr,但没有什么能阻止你。]

嗯,您可以编写delete ptr.get();

这样做几乎不可避免地会导致未定义的行为,无论是当其他共享所有者使用他们的shared_ptr访问现在已删除的对象时,还是当该对象的最后一个shared_ptr被销毁,并且该对象再次被删除时。

所以不,你不应该。

shared_ptr的目的是管理一个没有任何"人"有权利或责任删除的对象,因为可能有其他人共享所有权。所以你也不应该想要。

如果你想模拟计数递减,你可以在堆上手动完成,如下所示:

int main(void) {
    std::shared_ptr<std::string>* sp = new std::shared_ptr<std::string>(std::make_shared<std::string>(std::string("test")));
    std::shared_ptr<std::string>* sp2 = new std::shared_ptr<std::string>(*sp);
    delete sp;
    std::cout << *(*sp2) << std::endl;    // test
    return 0;
}

或者在使用std::shared_ptr::reset()的堆栈上,如下所示:

int main(void) {
    std::shared_ptr<std::string> p = std::make_shared<std::string>(std::string("test"));
    std::shared_ptr<std::string> p2 = p;
    p.reset();
    std::cout << *p2 << std::endl;    // test
    return 0;
} 

但它并没有那么有用。

您不能强制其引用计数为零

想想这需要什么才能奏效。你需要去每个使用shared_ptr的地方并清除它

如果您确实强制删除共享指针并将其设置为NULL,那么它就像一个weak_ptr。然而,代码中使用shared_ptr的所有位置都没有准备好,并且期望持有有效的指针。他们没有理由检查NULL,所以这些代码会崩溃。

在某些(非常?)罕见的情况下,显式删除会派上用场。

除了显式删除外,有时在"删除"共享指针时,还必须显式销毁它!

当与C代码接口时,将shared_ptr作为不透明值传递时,事情可能会变得奇怪。

例如,我有以下内容来向Lua脚本语言传递对象,该语言是用C编写的。(www.Lua.org)

static void push( lua_State *L, std::shared_ptr<T> sp )
{
    if( sp == nullptr ) {
        lua_pushnil( L );
        return;
    }
    // This is basically malloc from C++ point of view.
    void *ud = lua_newuserdata( L, sizeof(std::shared_ptr<T>));
    // Copy constructor, bumps ref count.
    new(ud) std::shared_ptr<T>( sp );
    luaL_setmetatable( L, B::class_name );
}

所以这是某个malloc内存中的一个shared_ptr。相反的是。。。(在Lua垃圾收集对象并释放它之前调用设置)。

static int destroy( lua_State *L )
{
    // Grab opaque pointer
    void* ud = luaL_checkudata( L, 1, B::class_name );
    std::shared_ptr<T> *sp = static_cast<std::shared_ptr<T>*>(ud);
    // Explicitly called, as this was 'placement new'd
    // Decrements the ref count
    sp->~shared_ptr();
    return 0;
}