我想看看 push_back 和 emplace_back 之间的区别,因为在几个地方我读到了建议,因为现在最好使用 emplace_back,因为“它可以完成 push_back 可以做的所有事情,甚至更多”,所以我希望 ti 更有效。但令我惊讶的是
#include <iostream>
#include <vector>
class A
{
public:
A() {std::cout << "A const" << std::endl;}
~A() {std::cout << "A dest" << std::endl;}
A(const A& a) {std::cout << "A copy const" << std::endl;}
A(A&& a) {std::cout << "A move const" << std::endl;}
A& operator=(const A& a) {std::cout << "A copy operator=" << std::endl; return *this; }
A& operator=(A&& a) {std::cout << "A move operator=" << std::endl; return *this; }
};
int main () {
std::vector<A> va;
std::cout <<"push:" << std::endl;
va.push_back(A());
std::cout <<std::endl<< "emplace:" << std::endl;
va.emplace_back(A());
std::cout <<std::endl<< "end:" << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出是
push:
A const
A move const
A dest
emplace:
A const
A move const
A copy const
A dest
A dest
end:
A dest
A dest
Run Code Online (Sandbox Code Playgroud)
emplace_back 调用 move 构造函数,然后在 push_back 只调用一个 move const 时复制一个。我检查了 g++ (Ubuntu 7.4.0-1ubuntu1~16.04~ppa1) 7.4.0 和online C++ shell。我错过了什么吗?
J. *_*rez 10
push_back 效率不高,您观察到的结果是由于矢量本身调整了大小。
当您调用emplaceafter 时push_back,向量必须调整自身大小以为第二个元素腾出空间。这意味着它必须移动A原来在向量内的emplace看起来更复杂。
如果您事先在向量中保留了足够的空间,则不会发生这种情况。注意对va.reserve(2)afterva创建的调用:
#include <iostream>
#include <vector>
class A
{
public:
A() {std::cout << "A const" << std::endl;}
~A() {std::cout << "A dest" << std::endl;}
A(const A& a) {std::cout << "A copy const" << std::endl;}
A(A&& a) {std::cout << "A move const" << std::endl;}
A& operator=(const A& a) {std::cout << "A copy operator=" << std::endl; return *this; }
A& operator=(A&& a) {std::cout << "A move operator=" << std::endl; return *this; }
};
int main () {
std::vector<A> va;
// Now there's enough room for two elements
va.reserve(2);
std::cout <<"push:" << std::endl;
va.push_back(A());
std::cout <<std::endl<< "emplace:" << std::endl;
va.emplace_back(A());
std::cout <<std::endl<< "end:" << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
对应的输出是:
push:
A const
A move const
A dest
emplace:
A const
A move const
A dest
end:
A dest
A dest
Run Code Online (Sandbox Code Playgroud)
我们能让事情变得更有效率吗?是的!emplace_back接受您提供的任何参数,并将它们转发到A的构造函数。因为A有一个不带参数的构造函数,所以你也可以emplace_back不带参数使用!换句话说,我们改变
va.emplace_back(A());
Run Code Online (Sandbox Code Playgroud)
到
va.emplace_back(); // No arguments necessary since A is default-constructed
Run Code Online (Sandbox Code Playgroud)
这导致没有复制,也没有移动:
push:
A const
A move const
A dest
emplace:
A const
end:
A dest
A dest
Run Code Online (Sandbox Code Playgroud)
关于向量调整大小的说明:重要的是要注意 的实现std::vector是智能的。如果A一直是平凡复制的类型,std::vector可能是就地能调整大小,无需额外复制使用类似的系统功能realloc。但是因为As的构造函数和析构函数都包含代码,realloc这里不能使用。