考虑一个类的两个实现:
struct S1 { std::vector< T > v; void push(T && x) { v.push_back(std::move(x)); } void push(T const & x) { push(T(x)); } void pop() { v.pop_back(); } void replace(T && x) { pop(); push(std::move(x)); } void replace(T const & x) { replace(T(x)); } }; struct S2 { std::vector< T > v; void push(T x) { v.push_back(std::move(x)); } void pop() { v.pop_back(); } void replace(T x) { pop(); push(std::move(x)); } };
S1
的push
重载表达正是我想要的.S2
这push
是一种以不那么冗长的方式表达它的方式.
但我担心对象的过度移动构造存在缺陷.
现代编译器可以减少表达std::move(T(std::move(t)))
对std::move(t)
一些t
地方decltype(t)
是T&
?现代编译器可以优化不必要的移动吗?或者这是否被标准禁止?
不,除了as-if优化之外,这种省略不合法.
现在,如果foo()
是一个返回a的表达式T
,那么S{}.push(foo())
可以忽略从返回值foo()
到参数的push
移动:只进行一次移动.
但是,如果我们S{}.push(std::move(foo())
,明确std::move
阻止了省略的可能性.
通常更好的方法是基于动作的操作而不是基于推送的操作.
templatevoid emplace(Args&&...args) { v.emplace_back( std::forward (args)... ); }
这允许您传递参数以构造T
对象,并使其直接构建在接收器(向量)中,而不是移动或复制到其中.
可选:
template()...))* =0 > void emplace(Args&&...args) { v.emplace_back( std::forward (args)... ); }
如果你想要SFINAE支持.评论说"我们希望在T
这里建造一个",如果不是很明显,也是礼貌的.