emplace_back() 和 push_back() 的区别,就在于底层实现的机制不同。

push_back() 向容器尾部添加元素时,首先会创建这个元素,然后再将这个元素拷贝或者移动到容器中(如果是拷贝的话,事后会自行销毁先前创建的这个元素)。使用到了拷贝构造函数

而 emplace_back() 在实现时,则是直接在容器尾部创建这个元素,省去了拷贝或移动元素的过程。直接使用构造参数列表来添加元素的方法,它会使用到了移动构造函数 move(不用拷贝一个复制品)。

源码实现的区别:

_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() 函数而言,本质上是一个类型转换函数

新版本的原型展示:

void push_back(const value_type& x);

void push_back(value_type&& x);

<typename... Args> reference emplace_back(Args&&... args);


两者区别:

push_back:传入一个事先存在的元素对象,调用的是拷贝或移动构造来生成这个新压入的元素对象:construct(*des, class_name&|&& x)

emplace_back:多个事先存在的对象,调用示义:construct(*des, other_type &x|&&x, type_name &|&&,...)

可以看见,emplace_back传参不定,编译器需要在调用时才生成具体的实现,push_back只是emplace_back的两个偏移化版本。  

push_back只能用类中的拷贝或移动构造,而emplace_back还可以是类中的其他多参数的构造函数(自定义的类,调用的构造函数也由自己定义,没有定义或没有就会报错),这是优点也是缺点(代码翻倍)

&&在普通函数中作为参数时,是万能引用,并不是右值引用,在函数体中会使用forward完美转发,调用时是复制或移动,和你传的值有关,你传左值它就用左值版本,传右值就用右值版本。

如果一个类没有上诉的拷贝或移动构造,则不能用于STL容器中,如果没有相应参数类型的构造实现,emplace_back编译不过,找不到它需要的对应构造函数。

move和copy构造唯一区别:move时,指针属性只是简单的拷贝指针,而copy中,指针属性被拷贝的同时,它所指的具体内容也还需要深度copy下去。

在实现类的两个构造时特别要注意这一点,move中要将旧对象的内部指针属性置nullptr,这意味着相应的对象不再适合使用了(这就是对象必须是临时对象的原因!转移后,内部的指针属性失效!)

move和copy的性能对比:正如上说,move只是指针优化,如果类本身没有指针属性,则它不需要move,我们也不必强制move不可,copy和move在内置类型和简单类型(指无指针属性、即构造时不需要new)没区别

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐