【问题标题】:emplace_back() vs push_back() for vectoremplace_back() 与 push_back() 的向量
【发布时间】:2021-10-12 08:31:17
【问题描述】:

我知道这个问题被问了很多,我看到很多解释都引用了“emplace_back 构造,push_back() 构造和复制”。有些帖子问为什么 emplace_back 调用复制构造函数,因为它们没有为向量保留内存。

但是对于以下情况,我无法弄清楚 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;
}

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

【问题讨论】:

标签: c++ stdvector rvalue-reference move-constructor emplace


【解决方案1】:

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(int)1 构造,然后传递给push_back,该元素由Int 的移动构造函数从临时构造。 IE。比 v.emplace_back(1); 多了一个移动构造函数调用。

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

正如@JeJo 建议的那样,emplace_backpush_back 自 C++17 以来还有另一个区别。 emplace_back 返回对插入元素的引用,而 push_back 不返回任何内容。

【讨论】:

  • @JeJo but the insert returns nothing. 也许我误解了,但std::vector::insert 不会返回“无”。它返回一个迭代器。
  • @JeJo push_back 什么也不返回。无论如何感谢您的提醒,这是我没有掌握的新功能。
猜你喜欢
  • 1970-01-01
  • 2011-05-17
  • 2014-01-03
  • 2020-09-12
  • 2018-11-15
  • 2019-05-22
  • 1970-01-01
  • 2015-05-19
相关资源
最近更新 更多