给出一个向量
std::vector<BigObject> v;
和工厂功能
BigObject genBigObject();
我想避免复制BigObject
实例。
哪个更快?
v.push_back(genBigObject());
或
v.push_back(std::move(genBigObject()));
我能否依靠复制省略会一直发生的事实? (我可以删除BigObject
上的副本构造函数,但是,好吧...)
答案 0 :(得分:10)
std::move()
的目的是采用一个 lvalue 并将其视为 rvalue ,以明确表示其后的其他功能可以蚕食如果他们愿意,可以查看对象的内部。
genBigObject()
已经是一个右值。您无需move()
就可以使其成为一体-move()
根本没有为您提供任何有价值的东西。因此,请不要这样做。您甚至不需要研究下游实际发生什么问题-move()
可以向代码和读者发出信号,表明您正在做某些可能不安全的事情,但是在这种情况下...
对于这种特定于 的情况,无论如何,您都在调用push_back()
的右值引用重载-这会触发临时对象的临时实现。临时实现具体是由于对push_back()
的调用还是对move()
的较早调用而没有关系。
答案 1 :(得分:2)
此处不会发生清除,有关详细信息,请参见@Barry的答案。
简而言之,push_back
不支持省略号;它需要一个右值引用或一个常量左值引用。
您有一个实际值;调用std::move
会将该右值强制转换为右值引用,这是毫无意义的操作。就像int x = 7; static_cast<int&>(x);
一样-几乎是无意识的,有时是悲观的。
要解决您的核心关切,即您想省事,我们可以做些什么。
您可以通过一些工作来消除BigObject
的构造:
template<class F>
struct emplacer {
F f;
operator std::result_of_t<F&&()>()&&{ return std::forward<F>(f)(); }
operator std::result_of_t<F&()>()&{ return f(); }
};
template<class T>
emplacer(T&&)->emplacer<T&&>;
现在您可以执行以下操作:
v.emplace_back( emplacer{ &getBigObject });
和BigObject
将直接放置到向量缓冲区中(除非过度贪婪的BigObject
构造函数)。
Live example(请注意,完全没有输出;我们在向量中生成了100个BigObject,在移动时生成了零)。