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));
一样传递一个Int
给emplace_back
,如上所述,临时的Int
被转发给Int
的移动构造元素的构造函数,它与 v.push_back(Int(1));
.
做同样的事情
正如@JeJo 所建议的,自 C++17 以来,emplace_back
和 push_back
之间还有另一个区别。 emplace_back
returns 对插入元素的引用,而 push_back
returns 什么都没有。
我知道很多人都问过这个问题,我看到很多解释都引用了“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));
一样传递一个Int
给emplace_back
,如上所述,临时的Int
被转发给Int
的移动构造元素的构造函数,它与 v.push_back(Int(1));
.
正如@JeJo 所建议的,自 C++17 以来,emplace_back
和 push_back
之间还有另一个区别。 emplace_back
returns 对插入元素的引用,而 push_back
returns 什么都没有。