emplace_back() 对比 push_back() 向量

emplace_back() vs push_back() for vector

我知道很多人都问过这个问题,我看到很多解释都引用了“emplace_back 就地构造,push_back() 构造和复制”。有帖子问为什么emplace_back调用拷贝构造函数,因为他们没有为vector预留内存。

但是对于下面的情况,我无法弄清楚 emplace_back() 比 push_back() 实现的更多。有些回答说“你需要为 emplace_back() 实现一个移动构造函数才能工作”但是 push_back() 也可以利用移动构造函数。那么有什么区别呢

#include <iostream>
#include <vector>
using namespace std;
 

class Int{
    public:
    int* p;
    Int(int x): p(new int(x)) {cout<<"constructor called for "<<*p<<endl;}
    Int(const Int& x): p(new int(*(x.p))) {cout<<"copy constructor called for "<<*p<<endl;}
    ~Int(){
        if (p!= nullptr) {cout<<"destructor called for "<<*p<<endl;}
        else{cout<<"destructor called for null ptr"<<endl;}   
        delete p; 
    }
    
    Int(Int&& x): p(x.p) {
        x.p = nullptr; 
        cout<<"move constructor called for "<<*p<<endl;  // move constructor, remove to test emplace_back()
        }
};

int main(){
    vector<Int> v;
    v.reserve(1);
    v.emplace_back(Int(1));  // can switch to push_back()
    // v.push_back(Int(1));
    cout<<"end program"<<endl;
}

对我来说,似乎这两种方法都调用没有移动构造函数的复制构造函数,如果有移动构造函数则调用移动构造函数。

emplace_back 通过将参数转发给元素类型的构造函数来就地构造元素,因此您可以

v.emplace_back(1); // forwarding 1 to Int::Int(int) to construct the element directly

push_back 总是需要一个元素,即 Int。当您将 1 作为 v.push_back(1); 传递给它时,会发生隐式转换。 (Int::Int(int)1 构造临时 Int 然后传递给 push_back,稍后由 Int 的移动构造函数从临时构造元素。 IE。比 v.emplace_back(1);.

多一次移动构造函数调用

你也可以像v.emplace_back(Int(1));一样传递一个Intemplace_back,如上所述,临时的Int被转发给Int的移动构造元素的构造函数,它与 v.push_back(Int(1));.

做同样的事情

正如@JeJo 所建议的,自 C++17 以来,emplace_backpush_back 之间还有另一个区别。 emplace_back returns 对插入元素的引用,而 push_back returns 什么都没有。