尝试使用带有forward-declaration声明的类型的auto_ptr
时,如下所示:
class A;
...
std::auto_ptr<A> a;
未调用A
的析构函数(显然,因为auto_ptr
内部delete
是底层指针,并且不能调用不完整类型的析构函数。
但是,相同的代码工作正常,并且在使用std::shared_ptr
而不是std::auto_ptr
时会调用析构函数。
怎么解释?
答案 0 :(得分:35)
可以使用不完整的类型声明shared_ptr
,是的。在初始化或重置之前,不需要完成该类型。
初始化或重置shared_ptr
以指向新对象时,它会创建一个可用于销毁对象的“删除器”。例如,请考虑以下事项:
// somewhere where A is incomplete:
std::shared_ptr<class A> p;
// define A
class A { /* ... */ };
p.reset(new A());
当您致电reset
时,A
已完成,因为您正在使用new
创建其实例。 reset
函数在内部创建并存储一个删除器,该删除器将用于使用delete
销毁对象。由于此处A
已完成,因此delete
将做正确的事。
通过执行此操作,shared_ptr
在声明A
时不要求shared_ptr<A>
完成;它只需要在调用获取原始指针的A
构造函数或使用原始指针调用shared_ptr
时完成reset
。
请注意,如果A
,当您执行这两项操作中的一项时,shared_ptr
将无法执行正确的操作并且行为未定义(这是在the documentation for boost::shared_ptr
中解释,这可能是学习如何正确使用shared_ptr
的最佳资源,无论您使用的是哪个版本的shared_ptr
(Boost,TR1,C ++ 0x等)。 ))。
但是,只要您始终遵循shared_ptr
的最佳使用惯例 - 值得注意的是,如果您始终使用指向{{1}的调用产生的指针直接初始化并重置shared_ptr
- 你不必担心违反这条规则。
此功能不是免费的:new
必须创建并存储指向删除器仿函数的指针;通常这是通过将删除器存储为存储强弱引用计数的块的一部分,或者通过将指针作为指向删除器的块的一部分来存储(因为您可以提供自己的删除器)。
shared_ptr
(和auto_ptr
也被设计为没有任何开销:对它的操作应该与使用哑指针一样有效。因此,unique_ptr
没有此功能。