为什么在标准容器中使用std::auto_ptr<>是错误的?


auto_ptr的复制语义与容器不兼容。

具体来说,将一个auto_ptr复制到另一个auto_ptr并不会创建两个相等的对象,因为其中一个已经失去了指针的所有权。

更具体地说,复制auto_ptr会导致其中一个副本放弃指针。这些元素中哪一个仍然保留在容器中没有定义。因此,如果将auto_ptrs存储在容器中,可能会随机失去对指针的访问。


STL容器需要能够复制存储在其中的项,并且被设计为期望原始和副本是等效的。自动指针对象有一个完全不同的契约,通过复制创建所有权的转移。这意味着auto_ptr容器将根据使用情况表现出奇怪的行为。

在Effective STL (Scott Meyers)第8项中有关于可能出错的详细描述,在Effective c++ (Scott Meyers)第13项中也有不那么详细的描述。


STL容器存储包含项的副本。当复制auto_ptr时,它将旧的ptr设置为null。许多容器方法都被这种行为破坏了。


c++标准规定STL元素必须是“可复制构造的”和“可赋值的”。换句话说,一个元素必须能够被赋值或复制,并且这两个元素在逻辑上是独立的。auto_ptr不满足此要求。

以下面的代码为例:

class X
{
};

std::vector<std::auto_ptr<X> > vecX;
vecX.push_back(new X);

std::auto_ptr<X> pX = vecX[0];  // vecX[0] is assigned NULL.

为了克服这个限制,你应该使用std::unique_ptr, std::shared_ptr或std::weak_ptr智能指针或boost等价物(如果你没有c++ 11)。下面是这些智能指针的boost库文档。


两篇关于这个主题的超级优秀的文章:

智能指针-什么,为什么,哪个? 本周大师第25名


c++ 03标准(ISO-IEC 14882-2003)在第20.4.5条第3段中说:

[…] 【注:[…] auto_ptr不满足标准库的CopyConstructible和Assignable要求 容器元素,从而实例化标准库容器 使用auto_ptr会导致未定义的行为。-结束注]

c++ 11标准(ISO-IEC 14882-2011)在附录D.10.1第3段中规定:

[…] 注意:[…auto_ptr实例满足 MoveConstructible和MoveAssignable,但不符合要求 CopyConstructible和CopyAssignable。-结束注]

c++ 14标准(ISO-IEC 14882-2014)在附录C.4.2中说明 附件D:兼容性特性:

更改:类模板auto_ptr、unary_function和binary_function,函数模板random_shuffle和 函数模板(及其返回类型)ptr_fun, mem_fun Mem_fun_ref, bind1st和bind2nd没有定义。 理由:被新功能取代。 对原有特性的影响:使用这些类模板和函数模板的有效c++ 2014代码可能无法在此编译 国际标准。