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.