为什么使用std::auto_ptr<>
标准容器是错误的?
6 回答
C++ 标准规定 STL 元素必须是“可复制构造的”和“可赋值的”。换句话说,一个元素必须能够被分配或复制,并且这两个元素在逻辑上是独立的。std::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.
要克服此限制,如果您没有 C++11 ,则应使用std::unique_ptr
、std::shared_ptr
或智能指针或 boost 等效项。这是这些智能指针的 boost 库文档。std::weak_ptr
的复制语义与auto_ptr
容器不兼容。
具体来说,将一个对象复制auto_ptr
到另一个对象并不会创建两个相等的对象,因为其中一个对象失去了对指针的所有权。
更具体地说,复制 anauto_ptr
会导致其中一个副本放开指针。其中哪些保留在容器中未定义。因此,如果您存储auto_ptrs
在容器中,您可能会随机失去对指针的访问权限。
关于这个主题的两篇超级优秀的文章:
STL 容器需要能够复制您存储在其中的项目,并且旨在期望原始和副本是等效的。自动指针对象具有完全不同的合同,复制会产生所有权转移。这意味着 auto_ptr 的容器会表现出奇怪的行为,具体取决于使用情况。
在 Effective STL (Scott Meyers) 第 8 条中有详细描述可能出错的地方,在 Effective C++ (Scott Meyers) 第 13 条中也有不太详细的描述。
STL 容器存储包含项目的副本。复制 auto_ptr 时,会将旧的 ptr 设置为 null。这种行为破坏了许多容器方法。
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 代码可能无法在本国际标准中编译。