shared_ptr删除对象

时间:2011-09-09 20:43:10

标签: c++ boost shared-ptr

void ClassName::LocalMethod( )
{
    boost::shared_ptr<ClassName> classNamePtr( this );

    //some operation with classNamePtr
    return;
}

这里的对象在从LocalMethod()返回时被释放,因为classNamePtr超出了范围。不是shared_ptr足够聪明,知道ClassName对象仍在范围内而不是删除它吗?

2 个答案:

答案 0 :(得分:4)

为对象创建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>

答案 1 :(得分:3)

  

shared_ptr是否足够聪明,无法知道ClassName对象是什么   还在范围内而不是删除它?

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

如果classNamePtr之外没有ClassName::LocalMethod()的副本,,您可以传递一个在构建classNamePtr时不执行任何操作的删除工具。 Here's an example of a custom deleter being used to prevent a shared_ptr from deleting its pointee。根据您的情况调整示例:

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_thisshared_ptr获取this。请注意,只有现有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();

这是更合适的“官方”方法,并且它比无效删除方法更加虚伪。

也可能是您实际上不需要首先创建shared_ptr。评论//some operation with classNamePtr部分的内容是什么?可能有比前两种方式更好的方式。