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


217

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


5
绝对是+1,因为我已经看到很多人弄错了。这是一个很好的问题。
twokats

请另外阅读相关项目。从另一个方面考虑这个问题。可能有助于了解有关auto_ptr和STL容器的更多信息。 stackoverflow.com/questions/8630552/...
nickolay


1
move语义和unique_ptr目的是为了避免与...有关的问题auto_ptr。在C ++ 03中,由于auto_ptr编译器和语言无法区分l和r值,因此该语言的功能不足以编写可在所有情况下正确安全运行的类,因此使用了一些“ hacks”来获得所需的行为。大多数时候。
Phil1970年

尼斯文章:STL容器和auto_ptr对象-他们为什么不混合quantstart.com/articles/...
alfC

Answers:


124

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_ptrstd::shared_ptrstd::weak_ptr智能指针或升压等效项。 这是这些智能指针的Boost库文档。


7
如果不需要共享所有权,则还应考虑Boost指针容器。
2009年

4
unique_ptr还禁止复制,因此某些STL操作将无法正常运行,除非它们可以使用其移动语义。
Mike Weller

4
“要克服此限制,您应该使用std::unique_ptr“:类模板只能由于移动语义而存在(其规范要求右值引用),因此从根本上要求C ++ 11。但是(和相关的)C ++ 11标准不再说STL元素类型必须是“可复制构造的”和“可分配的”。具有可移动性和可移动性就足够了。实际上,unique_ptr实例只能是可移动构造的和可移动分配的。但是auto_ptr实例也是如此!因此,在C ++ 11中,您可以使用auto_ptr进行操作unique_ptr
Marc van Leeuwen 2014年

@MarcvanLeeuwen,除非您resetrelease需要的人
棘手怪胎

2
@ratchetfreak:嗯,我不明白。什么?“除非您resetrelease”,否则我的评论中看不到这有什么用。请注意这两个auto_ptrunique_ptr具有这两种方法,和他们做同样的事情,在这两种情况下。
Marc van Leeuwen 2014年

66

拷贝语义auto_ptr不与容器兼容。

特别是,将一个副本复制auto_ptr到另一个副本不会创建两个相等的对象,因为一个对象已经失去了对指针的所有权。

更具体地说,复制an auto_ptr会使副本之一放开指针。这些容器中剩余的哪些未定义。因此,如果将指针存储auto_ptrs在容器中,则可能会随机失去对指针的访问。


39

关于该主题的两篇超优秀文章:


因为我认为在随后的两年中,他可能处理了眼前的问题。
小狗

27
@DeadMG:是的,您是正确的。但这不是我的目的。auto_ptr我敢肯定,如果某人某个时间来此线程并想学习和学习一些东西,那么这些链接将很有帮助。
Lazer 2010年

最近有很多重复的内容。
小狗

8
@DeadMG:这个问题没有被重复,因此可以扩展。Lazer说了这里没有说过的话。我猜他是偶然来的。
塞巴斯蒂安·马赫

第二个链接中的分析(在呼叫后分析问题)sort()比此处的所有答案都清晰。
chaosink

17

STL容器需要能够复制您存储在其中的项目,并且旨在使原始和副本具有相同的功能。自动指针对象具有完全不同的契约,因此复制会创建所有权转移。这意味着auto_ptr的容器将表现出奇怪的行为,具体取决于用法。

在有效的STL(Scott Meyers)项目8中有可能出错的详细描述,在有效的C ++(Scott Meyers)项目13中也没有那么详细的描述。


12

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


但是,当使用unique_ptr时,您会得到几乎相同的结果,因为只有一个unique_ptr可以拥有该对象的所有权?
Tracer 2014年

2
unique_ptr像任何适当的C ++ 11对象一样,@ Tracer 仅在移动构造或-assigned时才可以转移其资源的所有权,从而确保程序员必须故意传递一个std::move(sourceObject)或临时值,而不是传递一个左值并以直觉/不可预测的方式对其进行突变副本分配...,这是这里的一个核心问题,在这里已得到充分强调auto_ptr
underscore_d

4

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代码可能无法在本国际标准中进行编译。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.