void ClassName::LocalMethod( )
{
boost::shared_ptr<ClassName> classNamePtr( this );
//some operation with classNamePtr
return;
}
这里的对象在从LocalMethod()返回时被释放,因为classNamePtr超出了范围。不是shared_ptr足够聪明,知道ClassName对象仍在范围内而不是删除它吗?
答案 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
的复制构造函数在p1
和p3
之间创建共享所有权。请注意,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_this
从shared_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
部分的内容是什么?可能有比前两种方式更好的方式。