在C++11之后,vector容器中添加了新的方法:emplace_back(),和push_back()一样的是都是在容器末尾添加一个新的元素进去,不同的是emplace_back()在效率上相比较于push_back()有了一定的提升。

1.push_back()方法

首先分析较为简单直观的push_back()方法。对于push_back()而言,最开始只有void push_back( const T& value );这个函数声明,后来从C++11,新加了void push_back( T&& value )函数,以下为C++中的源码实现:
/** * 以下程序来自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 >= 201103L void push_back(value_type &&__x) { emplace_back(std::move(__x)); } #endif
在C++20之后,对这两个重载方法进行了修改,变成了constexpr void push_back( const T& value );以及constexpr void push_back( T&& value );。详情参考http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1004r2.pdf版本修改计划。

2.emplace_back()方法

emplace_back()是从C++11起新增到vector中的方法,最初的函数声明为:
templatevoid emplace_back( Args&&... args );
之后在C++14之后,将无返回值void改为了返回对插入元素的引用:
templatereference emplace_back( Args&&... args );
在STL源码中,可以看到emplace_back()的实现是这样的:
/** * 以下程序来自STL源码 bits/vector.tcc */ templatetemplate#if __cplusplus > 201402L typename vector::reference #else void #endif vector::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)...); ++this->_M_impl._M_finish; // 更新当前容器大小 } else // 满了的话重新申请内存空间,将新的元素继续构造进来,并且进行类型转换 _M_realloc_insert(end(), std::forward(__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)...); // emplace_back() _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish, __x); // push_back()
对于std::forward()函数而言,本质上是一个类型转换函数,它的声明函数如下所示:
/** * 以下程序来自STL源码 bits/move.h * @brief Forward an lvalue. * @return The parameter cast to the specified type. * * This function is used to implement "perfect forwarding". */ templateconstexpr _Tp &&forward(typename std::remove_reference::type &__t) noexcept { return static_cast(__t); }
在强制类型转换中,将参数__t传递给对应类_Tp的构造函数,然后调用了该类的构造函数从而完成对象创建过程。
因此,在emplace_back()函数中,是支持直接将构造函数所需的参数传递过去,然后构建一个新的对象出来,然后填充到容器尾部的。

3. 直观区别

声明一个Person类,里面只有一个字段_age,在容器中存储该类的对象,方便于查看整个函数调用过程。
class Person { int _age; public: Person(int age) : _age(age) { cout