【问题标题】:Why unique_ptr works but auto_ptr doesn’t with STL为什么 unique_ptr 有效,但 auto_ptr 不适用于 STL
【发布时间】:2019-11-09 03:49:07
【问题描述】:

我在这些问题上提到了很多 StackOverflow 链接,其中auto_ptr 无法与 STL 很好地配合使用的原因是 std::auto_ptr<> 不满足可复制和可分配的要求(因为 auto_ptr 有一个假的复制构造函数,它基本上转移了所有权)。

但即使unique_ptr 也没有复制 ctor 和赋值运算符(已禁用),那么如何满足可复制构造和可分配的要求?

【问题讨论】:

  • 您是否有需要复制但与unique_ptr 配合使用的特定示例?

标签: c++ stl copy-constructor unique-ptr auto-ptr


【解决方案1】:

你正在向后看整个事情。

在 C++98/03 中,我们得到了auto_ptr。这种类型通过假装它支持复制语义来欺骗每个人,而实际上复制它所做的事情与复制操作非常不同。因此,任何依赖于提供复制语义的类型的类型,如某些容器,都不会很好地获得auto_ptr。当然,你只会在你的代码出现功能异常时才发现,而不是在编译时。

在 C++11 中,我们得到了 unique_ptr,这是一种明确不提供复制语义的类型。相反,它提供移动语义,并正确提供它们。因此,任何依赖于提供复制语义的类型的类型在给定 unique_ptr 时都将无法编译。

然而unique_ptr 之所以应运而生,完全是因为在 C++11 的语言中加入了移动对象的概念。当新概念被添加到语言中时,现有工具(如标准库要求)通常会相对于该语言功能进行重新评估。

例如,以前需要复制语义的类型不一定必须保留该要求。需要复制语义的 C++98/03 容器在 C++11 中更新为仅需要(noexcept)类型的移动语义。

所以并不是unique_ptr 满足了auto_ptr 没有满足的某些要求。只是语言更改为不再需要该要求,但auto_ptr 仍在对其所做的事情撒谎,因此为了向后兼容,我们创建了一种尊重新语言特性且不欺骗人的新类型。

【讨论】:

  • 您的回答值得在 stackoverflow 上发表 20 篇其他详细帖子。这就是我一直在寻找的 - 关于改变要求和 ptr 使用的标准变化。
【解决方案2】:

我假设您指的是在 STL 容器中使用智能指针。

auto_ptr 可以,但不应该使用,因为它的复制构造函数可能会意外移动数据(它是在 C++11 中添加带有右值引用的移动语义之前设计的)。

unique_ptr 没有复制构造函数,因此不能在 STL 容器中简单地使用它。复制指针的操作将不起作用,但这就是使其安全的原因。您仍然可以显式使用 move iterators 或 emplace 将不可复制的元素放入容器中。

在容器中使用unique_ptr 的示例如下: So can unique_ptr be used safely in stl collections?

【讨论】:

  • 是的。知道了。微不足道是指“总是”吗?
  • 不。只是你随便用vector<int> 做的一些事情不适用于unique_ptr。如果你 push_backunique_ptr,你会得到一个严重的错误。但是如果你emplace_back 一个,你可能不会。有关示例,请参见链接。
  • @parktomatomi push_back 与 unique_ptr 一起工作得很好,只要参数是右值。
【解决方案3】:

auto_ptr 看起来像可复制/可赋值,因为它有一个复制构造函数和赋值运算符。

问题在于它的拷贝构造函数和赋值没有实现拷贝语义,而是移动语义。这使得 auto_ptr 的接口令人惊讶,并使其无法在内部分配元素的容器中使用(例如向量)。

更糟糕的是,在向量中使用 auto_ptr 格式正确(没有编译错误),但没有有用的行为,这很容易导致未定义的行为(即严重的错误)。

但即使是 unique_ptr 也没有复制 ctor 和赋值运算符(已禁用)

unique_ptr 不需要是可复制构造或可分配的。对于大多数用例来说,移动可构造和可分配就足够了。

unique_ptr 可以替代auto_ptr 的所有用途,不存在auto_ptr 的问题。自 C++11 引入 unique_ptr 以及对移动的语言支持以来,auto_ptr 已被弃用,自 C++17 以来,auto_ptr 已从标准库中删除。

【讨论】:

  • 我的困惑更多的是“STL 的可复制和可分配的要求”,unique_ptr 仍未满足。而你给出的关于 的例子“使 auto_ptr 的接口令人惊讶,并使其在内部分配元素的容器(例如向量)中无法使用。” 最终结果在 unique_ptr 的情况下也是相同的- 即数据被移动而不是复制。 auto_ptr 通过复制来移动它,unqiue_ptr 通过移动来移动它。那么在这种情况下,我们更喜欢 unique_ptr 的变化
  • @anurag86 复制 unique_ptr 一点也不奇怪。完全可以预料,它不能被复制。如果您不这么认为,编译器会相对清楚地告诉您。
  • @anurag86 auto_ptr 没有任何变化。它总是一个有缺陷的设计。当 C++ 标准化时,根本没有更好的选择。通常建议在弃用之前避免使用它。改变的是 C++ 语言和移动语义的引入,特别是在语言中引入了 unique_ptr 类型。 Unique_ptr 是 auto_ptr 应该是的,但不可能是因为语言中没有移动语义。
  • 知道了。谢谢!
猜你喜欢
  • 1970-01-01
  • 2013-07-08
  • 1970-01-01
  • 2015-09-09
  • 1970-01-01
  • 2017-05-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多