【问题标题】:Why are there two overloads for vector::push_back?为什么vector::push_back有两个重载?
【发布时间】:2015-01-24 21:40:15
【问题描述】:

为什么vector::push_back 不采用转发引用而不是两个重载?我读过你想要重载左值和右值的唯一原因是如果你的函数对它们做了不同的事情,那么vector::push_back 的重载除了移动/复制之外有何不同?

【问题讨论】:

  • 我认为push_back的转发参考版本就叫emplace_back
  • @Barry emplace_back 将引用转发到元素类型的 构造函数 的参数。
  • @templateboy 我不明白重点。 push_back(T&&) 也将其参数移动到元素类型的构造函数中。
  • @Barry 不。 T 是向量的元素类型,但emplace_back 采用Args&&... args 并将args... 转发给构造函数,就像element_type(std::forward<Args>(args)...) 一样。在push_back 中没有这样做
  • 但如果value_type 有复制构造函数,那么emplace_back 可以用作push_back 的更通用版本。

标签: c++ c++11


【解决方案1】:

我这样做主要是因为情况如何演变。在 C++11 之前,只有:

vector<T>::push_back(const T&);

随着右值引用的引入,我推荐添加的重载:

vector<T>::push_back(T&&);

而不是将原始签名更改为:

template <class U> vector<T>::push_back(U&&);

做出此决定的部分原因是出于对向后兼容性(无论是否有保证)的一些担忧,并且为了缓解供应商和委员会其他成员对这是一个简单的添加功能的担忧,而不是更改现有功能。

如果我今天从头开始重新设计vector,我会认真考虑:

template <class U> vector<T>::push_back(U&&);

或者只是:

template <class ...Args> vector<T>::emplace_back(Args&& ...);

您可能想知道的更多细节在N1858 中。

为什么不按价值push_back

这个问题已被标记为重复:

Why do C++11 std containers have pass-by-ref and pass-by-rvalue insert/push methods?

问这个问题。所以我认为在这个答案中实际解决这个方面是礼貌的做法......

对于 lvalues 和 xvalues,与按引用解决方案相比,push_back(T) 将花费额外的移动构造。 xvalues 需要 2 次移动构造,而左值需要 1 次复制构造和 1 次移动构造。

相比之下,在当前设计中,左值需要 1 次复制构建,而 xvalue 需要 1 次移动构建。

对于某些类型T,移动构造并不便宜。如果vector&lt;T&gt; 假设T 总是可以廉价移动,那将是一个糟糕的设计选择。例如,如果Tstd::array&lt;double, 100&gt; 会怎样?更改为按值设计将需要 2 次复制构造,而不是 1 次到 push_back(纯右值除外)。

按价值解决方案确实有优势,并且应该使用它的时间。只是vector&lt;T&gt;::push_back() 不是那个时代之一。

【讨论】:

  • 那么这两个函数中是否存在代码重复?
  • @templateboy:在 libc++ 实现中,内联的“快速路径”(不需要重新分配)中有非常少量的代码重复,但“慢速路径”是非内联的两个都重载到的私有函数。
  • v.push_back({aggregate_initialization}); 在您的“如果它今天设计的地方”下中断。完美的转发并不完美。
  • @HowardHinnant 你说如果你今天从头开始设计它,你会考虑只有 U&& 版本。左值不需要两次移动吗?对于搬家建设不便宜的类型,难道不是更糟吗?
  • @amfcosta:第一点:我说过考虑。我没有花时间测试和实施这些注意事项。第二点:不,左值将绑定到转发引用U&amp;&amp;,没有移动或复制。然后在内部代码将forward&lt;U&gt;(u) 构造一个T。假设UT,那就是1 个副本构造。我可能还会限制U,这样is_constructible&lt;T, U&gt;{}
猜你喜欢
  • 1970-01-01
  • 2013-08-18
  • 2014-02-16
  • 1970-01-01
  • 2018-11-26
  • 1970-01-01
  • 2016-11-15
  • 2021-09-06
相关资源
最近更新 更多