且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

为什么有两个重载的vector :: push_back?

更新时间:2023-02-14 17:27:28

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

 向量< T> :: push_back(const T& 

引入右值引用后,我推荐重载的添加

 矢量< T> :: push_back(T&& 

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

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

这个决定的一部分是由于一些关于向后兼容性(无论是否保证)以减轻供应商和其他委员会对这是简单的添加功能的关注,而不是对现有功能的更改。



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

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

或者只是:

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

您可能想知道的细节在 N1858



为什么不按 push_back $ c>按价值



问题已标记为重复的:



为什么C ++ 11 std container有pass-by-ref和pass-by-rvalue插入/ push方法?



这个问题。所以我想在这个答案中实际解决这个方面是有礼貌的事情...



对于左值和x值,一个 push_back (T)与参考解决方案相比会花费额外的移动。 xvalues将需要2个移动构造,并且lvalue将需要1个拷贝构造和1个移动构造。相反,对于当前设计,l​​values成本1拷贝构造和xvalues成本1移动施工。



对于一些类型 T ,移动施工不便宜。对于向量< T> 假定 T 总是便宜可移动,这将是一个差的设计选择。例如,如果 T std :: array< double,100> 更改为按值设计将需要2个副本构造,而不是1到 push_back (除了prvalues)。



按值解决方案确实有优势,并且应该使用它的次数。只是向量< T> :: push_back()不是这些时间之一。


Why doesn't vector::push_back take a forwarding reference instead of having two overloads? I've read that the only reason you'd want to overload on lvalues and rvalues is if your functions do something differently for them, so how do both overloads of vector::push_back differ other than moving/copying?

I did this largely just because of how the situation evolved. Prior to C++11, there was only:

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

With the introduction of rvalue references I recommended the addition of the overload:

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

instead of changing the original signature to:

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

Part of this decision was made because of some concerns about backward compatibility (whether warranted or not), and to ease concerns of both vendors and others on the committee that this was a simple addition of functionality, and not a change to existing functionality.

If I were redesigning vector from scratch today, I would seriously consider just having:

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

or perhaps just:

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

More details than you probably want to know about are in N1858.

Why not push_back by value?

This question has been marked as a duplicate of:

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

which asks this question. So I figured it would be the polite thing to do to actually address that aspect in this answer...

For lvalues and xvalues, a push_back(T) would cost an extra move construction compared to the by-reference solutions. xvalues would require 2 move constructions and lvalues would require 1 copy construction and 1 move construction.

In contrast, with the current design, lvalues cost 1 copy construction and xvalues cost 1 move construction.

For some types T, move construction is not cheap. It would be a poor design choice for vector<T> to assume that T is always cheaply movable. For example what if T is std::array<double, 100>? Changing to the by-value design would require 2 copy constructions instead of 1 to push_back (except for prvalues).

The by-value solution does have advantages, and times when it should be used. It is just that vector<T>::push_back() is not one of those times.