Shared_ptr删除对象

shared_ptr deletes the object

本文关键字:对象 删除 ptr Shared      更新时间:2023-10-16
void ClassName::LocalMethod( )
{
    boost::shared_ptr<ClassName> classNamePtr( this );
    //some operation with classNamePtr
    return;
}

在这里,对象从LocalMethod()返回时被释放,因为classNamePtr超出了作用域。难道shared_ptr不够聪明,知道ClassName对象仍然在作用域中,而不是删除它吗?

为对象创建shared_ptr意味着什么?这意味着shared_ptr的持有人现在对该对象具有所有权。所有权意味着对象将在他希望删除时被删除。当shared_ptr的持有者销毁其shared_ptr时,假设该对象没有其他shared_ptr,这将导致该对象潜在地被销毁。

shared_ptr是类的成员时,这意味着shared_ptr所指向的对象的生命周期至少与shared_ptr所指向的对象的生命周期相同。当shared_ptr在堆栈上时,这意味着shared_ptr指向的对象的生命周期至少与创建它的作用域一样长。对象一旦从栈上掉下来,就可以被删除。

唯一的时间你应该把一个指针包装到一个shared_ptr是当你分配对象最初。为什么?因为对象不知道它是否在shared_ptr中。它不可能知道。这意味着创建原始shared_ptr的人现在有责任将其传递给需要共享该内存所有权的其他人。共享所有权工作的唯一方式是通过shared_ptr复制构造函数。例如:

shared_ptr<int> p1 = new int(12);
shared_ptr<int> p2 = p1.get();
shared_ptr<int> p3 = p1;

shared_ptr的复制构造函数在p1p3之间创建共享所有权。注意p2 不与p1共享所有权。它们都认为自己拥有相同内存的所有权,但这与共享内存是不一样的。因为他们都认为他们有独特的所有权

因此,当三个指针被销毁时,将发生以下情况。首先,p3将被破坏。但由于p3和p1共享整数的所有权,整数还不会被销毁。接下来,p2将被破坏。因为它认为自己是该整数的唯一持有者,所以它将销毁该整数。

此时,p1指向已删除的内存。当p1被销毁时,它认为它是该整数的唯一持有者,因此它将销毁它。是坏的,因为它已经被销毁了。

你的问题是这样的。您在一个类的实例中。你需要调用你的一些函数,这些函数需要一个shared_ptr。但你只有this,这是一个常规指针。你是怎么做的?

你将得到一些建议enable_shared_from_this的例子。但是考虑一个更相关的问题:"为什么这些函数将shared_ptr作为参数?"

函数接受的指针类型表明该函数对其实参做什么。如果一个函数接受shared_ptr类型,这意味着它需要拥有指针。它需要共享内存的所有权。因此,查看代码并询问这些函数是否真的需要来获得内存的所有权。他们是否将shared_ptr长期存储在某个地方(即:在对象中),或者他们只是在函数调用期间使用它们?

如果是后者,那么函数应该使用裸指针,而不是shared_ptr。这样,它们就不能声明所有权。你的接口是自文档化的:指针类型解释了所有权。

然而,有可能你调用的函数确实需要共享所有权。然后你需要使用enable_shared_from_this。首先,您的类需要从enable_shared_from_this派生。然后,在函数中:

void ClassName::LocalMethod()
{
    boost::shared_ptr<ClassName> classNamePtr(shared_from_this());
    //some operation with classNamePtr
    return;
}

注意这里是有代价的。enable_shared_from_this在类中放置一个boost::weak_ptr。但是没有虚拟开销或类似的东西;它不会使类成为虚的。enable_shared_from_this是一个模板,所以你必须像这样声明它:

class ClassName : public boost::enable_shared_from_this<ClassName>

难道shared_ptr不够聪明,不能知道ClassName对象是还在范围内,不删除吗?

这不是shared_ptr的工作原理。当您在构造shared_ptr时传递指针时,shared_ptr将承担对指针(在本例中为*this)的所有权。换句话说,由于shared_ptr现在拥有该指针,因此shared_ptr假定对该指针的整个生命周期具有完全的控制权。因此,最后一个拥有该指针的shared_ptr将删除它。

如果ClassName::LocalMethod()之外没有classNamePtr的副本,可以传递一个在构造classNamePtr时不做任何事情的delete。下面是一个使用自定义删除器来防止shared_ptr删除其指针的示例。使示例适应您的情况:

struct null_deleter // Does nothing
{
    void operator()(void const*) const {}
};
void ClassName::LocalMethod() 
{
    // Construct a shared_ptr to this, but make it so that it doesn't
    // delete the pointee.
    boost::shared_ptr<ClassName> classNamePtr(this, null_deleter()); 
    // Some operation with classNamePtr 
    // The only shared_ptr here will go away as the stack unwinds,
    // but because of the null deleter it won't delete this.
    return; 
}

也可以使用enable_shared_from_thisthis中获取shared_ptr。注意,成员函数shared_from_this()只有在现有的shared_ptr已经指向this的情况下才有效。

class ClassName : public enable_shared_from_this<ClassName> 
{ 
public: 
    void LocalMethod()
    { 
        boost::shared_ptr<ClassName> classNamePtr = shared_from_this(); 
    } 
} 
// ...
// This must have been declared somewhere...
shared_ptr<ClassName> p(new ClassName);
// before you call this:
p->LocalMethod();

这是一个更合适的,"官方"的方法,它比null delete方法要少得多。

也可能是您实际上不需要首先创建shared_ptr//some operation with classNamePtr注释部分包含什么内容?也许还有比前两种方法更好的方法