由于std :: vector :: push_back(obj)创建了对象的副本,在push_back()调用中创建它是否比预先更有效?
struct foo {
int val;
std::string str;
foo(int _val, std::string _str) :
val(_val), str(_str) {}
};
int main() {
std::vector<foo> list;
std::string str("hi");
int val = 2;
list.push_back(foo(val,str));
return 0;
}
// or
int main() {
std::vector<foo> list;
std::string str("hi");
int val = 2;
foo f(val,str);
list.push_back(f);
return 0;
}
答案 0 :(得分:3)
list.push_back(foo(val,str));
要求构造一个foo
对象,然后传递给向量。所以这两种方法都是相似的。
但是 - 使用这种方法,c ++ 11编译器会将foo
对象视为&#34;临时&#34; value(rvalue)并将使用void vector::push_back(T&&)
函数而不是void vector::push_back(const T&)
函数,并且在大多数情况下确实更快。您还可以使用先前声明的对象获取此行为:
foo f(val,str);
list.push_back(std::move(f));
另外,请注意(在c ++ 11中)您可以直接执行:
list.emplace_back(val, str);
答案 1 :(得分:2)
实际上有点牵扯。对于初学者,我们应该注意std::vector::push_back
在两种引用类型上重载:
void push_back( const T& value );
void push_back( T&& value );
当我们将左值传递给push_back
时,会调用第一个重载,因为只有左值引用类型可以绑定到左值,例如第二个版本中的f
。同样地,只有右值引用可以绑定到第一个版本中的右值。
它有所作为吗?只有你的类型受益于移动语义。您没有提供任何复制或移动操作,因此编译器将为您隐式定义它们。他们将分别复制/移动每个成员。因为如果字符串很长,std::string
(其中有成员)实际上确实可以从移动中受益,如果您选择不创建命名对象而是传递右值,则可能会看到更好的性能。
但是如果你的类型没有从移动语义中受益,你将看不出任何区别。所以总的来说,可以肯定地说你没有失去任何东西,并且可以通过“在通话中创造对象”来获得更多。
说了这么多,我们不能忘记矢量支持另一种插入方法。您可以通过调用std::vector::emplace_back
将foo
的构造函数的参数直接转发到向量中。那个将避免任何中间foo
对象,甚至是push_back
调用中的临时对象,并且将直接在向量打算为其提供的存储上创建目标foo
。因此,emplace_back
通常可能是最佳选择。
答案 2 :(得分:0)
你最好使用
emplace_back(foo(val,str))
如果您要创建新元素并将其推送到向量中。所以你要进行就地施工。
如果你已经创建了你的对象并且你确定你永远不会单独使用它来做另一条指令,那么你可以做到
push_back(std::move(f))
在这种情况下,您的f对象悬空,其内容由您的向量拥有。