Performance issues:

Before introducing the rvalue reference, the transfer constructor, and the transfer copy operator, it was common to use push_back() to add an rvalue element (a temporary object) to a container. The constructor was called first to construct the temporary object, and then the copy constructor was called to place the temporary object in the container. The original temporary variable is released. The problem with this is that resources for temporary variable requests are wasted.

With the introduction of an rvalue reference, the constructor and the shift constructor are called when the push_back() rvalue is shifted.

There is room for further optimization here with emplace_back(), which uses emplace_back() to add an element at the end of the container that is constructed in place and does not need to trigger copy and transfer constructs. Also, the call form is more concise, initializing the members of the temporary object directly from the parameters.

#include <vector> #include <string> #include <iostream> struct President { std::string name; std::string country; int year; President(std::string p_name, std::string p_country, int p_year) : name(std::move(p_name)), country(std::move(p_country)), year(p_year) { std::cout << "I am being constructed.\n"; } President(const President& other) : name(std::move(, country(std::move(, year(other.year) { std::cout << "I am being copy constructed.\n"; } President(President&& other) : name(std::move(, country(std::move(, year(other.year) { std::cout << "I am being moved.\n"; } President& operator=(const President& other); }; int main() { std::vector<President> elections; std::cout << "emplace_back:\n"; elections.emplace_back("Nelson Mandela", "South Africa", 1994); STD ::vector<President> reElections; STD ::vector<President> reElections; std::cout << "\npush_back:\n"; reElections.push_back(President("Franklin Delano Roosevelt", "the USA", 1936)); std::cout << "\nContents:\n"; for (President const& president: elections) { std::cout << << " was elected president of " << << " in " << president.year << ".\n"; } for (President const& president: reElections) { std::cout << << " was re-elected president of " << << " in " << president.year << ".\n"; }}

Source code analysis:


/** * brief Add data to the end of the %vector. * @param __x data to be added. ** This is a typical stack operation. The function creates an * element at the end of the %vector and assigns the given data * to it. Due to the nature of a %vector this operation can be * done in constant time if the %vector has preallocated space * available. */ void push_back(const value_type &__x) { if (this->_M_impl._M_finish ! = this->_M_impl._M_end_of_storage) {this->_M_impl._M_end_of_storage) {this->_M_impl. _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish, __x); ++this->_M_impl._M_finish; // update the number of elements in the current container} else // If it is full, reapply for space, copy the data, and then insert new data __x _M_realloc_insert(end(), __x); } // If the C++ version is C++11 or higher, this method is added from C++11. #if __cplusplus >= 201103L void push_back(value_type &&__x) {emplace_back(STD ::move(__x)); } #endif


/** */ vector. TCC */ template<typename _Tp, typename _Alloc> template<typename... _Args> #if __cplusplus > 201402L typename vector<_Tp, _Alloc>::reference #else void #endif vector<_Tp, _Alloc>::emplace_back(_Args &&... __args) { if (this->_M_impl._M_finish ! = this->_M_impl._M_end_of_storage) {this->_M_impl._M_end_of_storage = this->_M_impl. Struct (this->_M_impl, this->_M_impl._M_finish, STD ::forward<_Args>(__args)...) ; ++this->_M_impl._M_finish; } else // If the container is full, reapply the memory space, continue to construct the new element, and perform the type conversion _M_realloc_insert(end(), STD ::forward<_Args>(__args)...) ; #if __cplusplus > 201402L return back(); // After C++14, add a return value that returns the reference to the last element #endif} #endif

The main differences between emplace_back() and push_back() :

_Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish, std::forward<_Args>(__args)...) ; // emplace_back() _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish, __x); // push_back()

The STD ::forward() function is essentially a type conversion function: in a cast, __t is passed to the constructor of the corresponding class _TP, which is then called to complete the object creation process.

Therefore, in the emPlace_back () function, it is possible to simply pass in the arguments required by the constructor, build a new object, and then fill it at the end of the container.