我想看看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;
}
输出为
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
emplace_back调用move构造函数,然后在push_back仅调用一个move const时复制一个。我检查了g++(Ubuntu 7.4.0-1ubuntu1〜16.04〜ppa1)7.4.0和online C++ shell。
我想念什么吗?
最佳答案
push_back
效率不高,您观察到的结果归因于 vector 本身的大小调整。
当您在emplace
之后调用push_back
时, vector 必须自行调整大小以为第二个元素腾出空间。这意味着它必须移动最初在 vector 内的A
,从而使emplace
显得更复杂。
如果事先在 vector 中保留足够的空间,则不会发生这种情况。请注意va.reserve(2)
创建之后对va
的调用:
#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;
}
相应的输出是:
push:
A const
A move const
A dest
emplace:
A const
A move const
A dest
end:
A dest
A dest
我们可以提高效率吗? 是的!
emplace_back
接受您提供的任何参数,并将其转发给A
的构造函数。因为A
具有不带参数的构造函数,所以您也可以使用不带参数的emplace_back
!换句话说,我们改变va.emplace_back(A());
至
va.emplace_back(); // No arguments necessary since A is default-constructed
结果是没有拷贝,也没有移动:
push:
A const
A move const
A dest
emplace:
A const
end:
A dest
A dest
关于 vector 大小调整的注释:需要注意的是,
std::vector
的实现很聪明。如果A
是普通的可复制类型,则std::vector
可以使用类似于realloc
的系统功能就地调整大小而无需额外复制。但是,由于A
的构造函数和销毁包含代码,因此无法在此处使用realloc
。关于c++ - push_back比emplace_back更有效?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/62011157/