C++源码剖析push_back和emplace_back的区别

以c++11标准的std::vector为例,直接上源码:

// push_back
// 接收左值的重载版本
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
    _M_realloc_insert(end(), __x);
}
// 接收右值的重载版本
void push_back(value_type&& __x) { emplace_back(std::move(__x)); }

// emplace_back
// 万能引用,既接收左值又接收右值的唯一版本
template <typename _Tp, typename _Alloc>
template <typename... _Args>
void vector<_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)...);
}

比较源码得出结论:

  1. push_back有两个重载版本,分别是接收左值的版本,和接收右值的版本。
  2. emplace_back只有一个万能引用的版本,既能接收左值又能接收右值。
  3. push_back接收右值的版本其实就是调用的emplace_back。c++11后引入了右值引用和移动语义等概念,通过移动提高了代码效率。其实在c++11之前,push_back只有接收左值的版本,且没有emplace_back,但这个接收左值的版本因为是常量引用(const T&),所以也可以接收右值,但会多一次临时变量的拷贝构造,相比移动要低效些。所以在c++11后,push_back多了一个由emplace_back代理实现的右值引用的版本,提高效率,且客户端不用修改代码,只需重新编译一遍,就能够悄无声息地享受到此移动操作带来的效率提高。
  4. push_back的左值版本实现和emplace_back实现差异不大,区别主要在于emplace_back用了万能引用、可变参数模板、完美转发等特性,实现了对push_back左值版本的扩展。所以emplace_back可以接收多个参数实现就地构造,且总是能匹配到效率最高且正确的版本。但push_back只能接受一个参数,就是该容器的元素,然后匹配效率最高的版本,但无法通过参数就地构造。

可参考之前博文:一文读懂emplace_back和push_back的最主要区别

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值