当尝试使用一个被前向声明声明的类型来使用auto_ptr
时,像这样:
class A;
...
std::auto_ptr<A> a;
A
的析构函数没有被调用(显然是因为auto_ptr
内部删除了底层指针,而不完全类型的析构函数无法被调用)。
然而,当使用std::shared_ptr
代替std::auto_ptr
时,同样的代码可以正常工作,并且析构函数被调用。这是如何解释的?
当尝试使用一个被前向声明声明的类型来使用auto_ptr
时,像这样:
class A;
...
std::auto_ptr<A> a;
A
的析构函数没有被调用(显然是因为auto_ptr
内部删除了底层指针,而不完全类型的析构函数无法被调用)。
然而,当使用std::shared_ptr
代替std::auto_ptr
时,同样的代码可以正常工作,并且析构函数被调用。这是如何解释的?
一个shared_ptr
可以用不完整的类型进行声明。直到初始化或重置时,该类型才需要完整。
当你将一个shared_ptr
初始化或重置为指向一个新对象时,它会创建一个“删除器”,用于销毁该对象。例如,考虑以下情况:
// somewhere where A is incomplete:
std::shared_ptr<class A> p;
// define A
class A { /* ... */ };
p.reset(new A());
reset
时,因为您使用new
创建了一个实例,所以A
已经完成。 reset
函数创建并在内部存储了一个删除器,该删除器将用于使用delete
销毁对象。因为A
在此处是完整的,所以那个delete
会做正确的事情。shared_ptr
不要求在声明shared_ptr<A>
时A
必须是完整的;它只需要在使用原始指针的shared_ptr
构造函数被调用或者在调用带有原始指针的reset
时A
是完整的。A
不完整,则shared_ptr
将无法正常工作,并且行为是未定义的(这在boost::shared_ptr
的文档中有解释,这可能是学习如何正确使用shared_ptr
的最佳资源,无论您使用哪个版本的shared_ptr
(Boost、TR1、C++0x等)。)shared_ptr
的最佳使用实践,特别是如果您总是直接使用从new
调用结果的指针初始化和重置shared_ptr
,则不必担心违反此规则。shared_ptr
必须创建并存储指向删除器函数对象的指针;通常,这是通过将删除器存储为存储强引用计数和弱引用计数的块的一部分或具有指向删除器的指针的该块的一部分来完成的(因为您可以提供自己的删除器)。
auto_ptr
(以及unique_ptr
)旨在不带任何开销:对它的操作应该与使用愚蠢指针一样高效。因此,auto_ptr
没有这种功能。
std::make_shared<T>
。 - Kerrek SB