指向不完整类型的指针删除和智能指针

19

当尝试使用一个被前向声明声明的类型来使用auto_ptr时,像这样:

class A;
...
std::auto_ptr<A> a;

A的析构函数没有被调用(显然是因为auto_ptr内部删除了底层指针,而不完全类型的析构函数无法被调用)。

然而,当使用std::shared_ptr代替std::auto_ptr时,同样的代码可以正常工作,并且析构函数被调用。这是如何解释的?

1个回答

36

一个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构造函数被调用或者在调用带有原始指针的resetA是完整的。
请注意,如果在执行这两个操作之一时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没有这种功能。

7
这里是关于unique_ptr和shared_ptr完整性要求的摘要:http://home.roadrunner.com/~hinnant/incomplete.html - Howard Hinnant
2
如果你想要了解关于shared_ptr的高娱乐性的资料,可以观看STL on STL节目,时长一小时。另外还值得一提的是std::make_shared<T> - Kerrek SB
2
谢谢!这是一个更新的链接,其中包含unique_ptr和shared_ptr的完整性要求摘要:http://howardhinnant.github.io/incomplete.html - Howard Hinnant

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接