c++中push_back和emplace_back的区别

在学习emplace_back和push_back区别时,看到了以下这两篇文章,然而这两篇文章都会或多或少的问题,反而是评论区中给出了更为准确的答案。

https://blog.csdn.net/lemonxiaoxiao/article/details/108595548
https://zhuanlan.zhihu.com/p/213853588

第二篇文章中的竹子酒,他认为,push_back和emplace_back的区别在于一个仅能接收value_type&& 类型的参数,另一个参数类型是形参包(可以接收任意参数),因此才引发的一系列后续区别。

我们首先来看gcc-11中的stl_vector.h中push_back的源码, 其余容器的push_back的源码类似:

void
push_back(const value_type& __x)
      {
	if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage)
	  {
	    _GLIBCXX_ASAN_ANNOTATE_GROW(1);
	    _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish,
				     __x);
	    ++this->_M_impl._M_finish;
	    _GLIBCXX_ASAN_ANNOTATE_GREW(1);
	  }
	else
	  _M_realloc_insert(end(), __x);
      }

#if __cplusplus >= 201103L
      void
      push_back(value_type&& __x)
      { emplace_back(std::move(__x)); }

      template<typename... _Args>
#if __cplusplus > 201402L
	reference
#else
	void
#endif
	emplace_back(_Args&&... __args);
#endif

我们可以看到,这里push_back可以接受两种类型的参数,一是左值引用,二是右值引用.
而vector.tcc中emplace_back的源码为, 其他容器的emplace_back的源码类似:

if __cplusplus >= 201103L
  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)
	  {
	    _GLIBCXX_ASAN_ANNOTATE_GROW(1);
	    _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish,
				     std::forward<_Args>(__args)...);
	    ++this->_M_impl._M_finish;
	    _GLIBCXX_ASAN_ANNOTATE_GREW(1);
	  }
	else
	  _M_realloc_insert(end(), std::forward<_Args>(__args)...);
#if __cplusplus > 201402L
	return back();
#endif
      }
#endif

这里可以看到,emplace_back的形参为一个名为_Args&&的模板参数包,而在construct中使用std::forward将模板参数包强制类型转换为_Args类型的对象,在这个过程中调用了_Args class的构造函数. 以下是std::forward的源代码:

template<typename _Tp>
    _GLIBCXX_NODISCARD
    constexpr _Tp&&
    forward(typename std::remove_reference<_Tp>::type& __t) noexcept
    { return static_cast<_Tp&&>(__t); }

又因为,forward能够接受左值引用、右值引用、value_type的实参,所以,emplace_back也可以接受左值引用、右值引用、value_type类型的实参.
综上,在c++11中,emplace_back和push_back本质的区别是emplace_back能够接收模板参数包,所以emplace_back能够construct in place, 而push_back只能先construct再转换为右值再copy.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值