为什么在标准容器中使用std::auto_ptr<>
是错误的?
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.
std::unique_ptr
, std::shared_ptr
或std::weak_ptr
智能指针,如果您没有C++11,则可以使用boost等效指针。这是这些智能指针的boost库文档。
unique_ptr
也不允许复制,因此某些STL操作将无法正常工作,除非它们可以使用其移动语义。 - Mike Wellerstd::unique_ptr
:该类模板只能存在于 C++11 中,因为它需要移动语义(其规范要求 rvalue 引用)。然而(与此相关),C++11 标准不再要求 STL 元素类型必须是“可复制构造”和“可赋值”的;只要是可移动构造和可移动赋值的就足够了。实际上,unique_ptr
实例仅可移动构造和可移动赋值。但是,auto_ptr
实例也是如此!因此,在 C++11 中,使用 auto_ptr
所能做的与使用 unique_ptr
相同。 - Marc van Leeuwenreset
和release
”,我不明白它如何适用于我的评论中的任何内容。请注意,auto_ptr
和unique_ptr
都具有这两种方法,在这两种情况下它们的作用是相同的。 - Marc van Leeuwenauto_ptr 的复制语义与容器不兼容。
具体而言,将一个 auto_ptr
复制到另一个并不会创建两个相等的对象,因为一个已经失去了指针所有权。
更具体地说,复制一个 auto_ptr
会导致其中一个副本放弃指针。哪个副本留在容器中是未定义的。因此,如果您将 auto_ptr
存储在容器中,则可能随机丢失指针访问权限。
关于这个主题有两篇超级优秀的文章:
auto_ptr
等内容,这些链接肯定会很有帮助。 - Lazersort()
后分析问题的解释比这里所有答案都更清晰。 - chaosinkSTL容器需要能够复制存储在其中的项目,并且设计为期望原始项和副本是等效的。自动指针对象具有完全不同的合约,即复制创建所有权的转移。这意味着auto_ptr容器将根据使用情况展现出奇怪的行为。
在Effective STL(Scott Meyers)第8项中详细描述了可能出现的问题,而在Effective C++(Scott Meyers)第13项中则提供了不太详细的描述。
STL容器存储包含项的副本。当auto_ptr被复制时,它会将旧指针设置为null。许多容器方法因此行为而失效。
unique_ptr
就像任何合适的 C++11 对象一样,只能在移动构造或分配时传递其资源的所有权,确保程序员必须有意识地传递 std::move(sourceObject)
或临时对象,而不是传递 lvalue 并且不直观/不可预测地通过复制赋值进行突变...正如在这里彻底强调的那样,这是 auto_ptr
的一个核心问题。 - underscore_dC++03标准(ISO-IEC 14882-2003)在第20.4.5段第3句中说:
[...] [注意: [...] auto_ptr不满足标准库容器元素的CopyConstructible和Assignable要求,因此使用auto_ptr实例化标准库容器将导致未定义行为。— end note]
C++11标准(ISO-IEC 14882-2011)在附录D.10.1段第3句中说:
[...] 注意:[...] auto_ptr的实例满足MoveConstructible和MoveAssignable的要求,但不满足CopyConstructible和CopyAssignable的要求。— end note]
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代码可能无法在此国际标准中编译。
move
语义和unique_ptr
旨在避免与auto_ptr
相关的问题。在C++03中,语言不够强大,无法编写像auto_ptr
这样在所有情况下都能正确且安全地运行的类,因为编译器和语言无法区分左值和右值,所以有些“技巧”被用来大部分时间获得所需的行为。 - Phil1970