性能问题:

在引入右值援用,转移构造函数,转移复制运算符之前,通常应用push_back()向容器中退出一个右值元素(长期对象)的时候,首先会调用构造函数结构这个长期对象,而后须要调用拷贝构造函数将这个长期对象放入容器中。原来的长期变量开释。这样造成的问题是长期变量申请的资源就节约。

引入了右值援用,转移构造函数后,push_back()右值时就会调用构造函数和转移构造函数。

在这下面有进一步优化的空间就是应用emplace_back(),应用emplace_back()在容器尾部增加一个元素,这个元素原地结构,不须要触发拷贝结构和转移结构。而且调用模式更加简洁,间接依据参数初始化长期对象的成员。

#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(other.name)), country(std::move(other.country)), year(other.year)    {        std::cout << "I am being copy constructed.\n";    }    President(President&& other)        : name(std::move(other.name)), country(std::move(other.country)), 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::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 << president.name << " was elected president of "            << president.country << " in " << president.year << ".\n";    }    for (President const& president: reElections) {        std::cout << president.name << " was re-elected president of "            << president.country << " in " << president.year << ".\n";    }}

源码分析:

push_back:

/** *  以下程序来自STL源码 bits/stl_vector.h * *  @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) {        // 首先判断容器满没满,如果没满那么就结构新的元素,而后插入新的元素        _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish,                                 __x);        ++this->_M_impl._M_finish; // 更新以后容器内元素数量    } else        // 如果满了,那么就从新申请空间,而后拷贝数据,接着插入新数据 __x        _M_realloc_insert(end(), __x);}// 如果 C++ 版本为 C++11 及以上(也就是从 C++11 开始新加了这个办法),应用 emplace_back() 代替#if __cplusplus >= 201103Lvoid push_back(value_type &&__x) {    emplace_back(std::move(__x));}#endif

emplace_back:

/** *  以下程序来自STL源码 bits/vector.tcc */template<typename _Tp, typename _Alloc>template<typename... _Args>#if __cplusplus > 201402Ltypename vector<_Tp, _Alloc>::reference#elsevoid#endifvector<_Tp, _Alloc>::emplace_back(_Args &&... __args) {    if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage) {        // 同样判断容器是否满了,没满的话,执行构造函数,对元素进行结构,并执行类型转换        _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish,                                 std::forward<_Args>(__args)...);        ++this->_M_impl._M_finish; // 更新以后容器大小    } else        // 满了的话从新申请内存空间,将新的元素持续结构进来,并且进行类型转换        _M_realloc_insert(end(), std::forward<_Args>(__args)...);#if __cplusplus > 201402L    return back(); // 在 C++14版本之后,增加返回值,返回最初一个元素的援用#endif}#endif

emplace_back() 和 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()

对于std::forward() 函数而言,实质上是一个类型转换函数:
在强制类型转换中,将参数 __t 传递给对应类 _Tp 的构造函数,而后调用了该类的构造函数从而实现对象创立过程。

因而,在 emplace_back() 函数中,是反对间接将构造函数所需的参数传递过来,而后构建一个新的对象进去,而后填充到容器尾部的。