移动省略优化

Move elision optimization

考虑 class:

的两个实现
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)); }
};

S1push 重载正是我想要的。 S2push 是一种更简洁的表达方式。

但我担心对象的过度移动构造会带来不利影响。

对于某些 t,其中 decltype(t)T&,现代编译器能否将表达式 std::move(T(std::move(t))) 简化为 std::move(t)?现代编译器可以优化掉不必要的动作吗?或者这是标准禁止的?

不,除了在 as-if 优化下,省略是不合法的。

现在,如果 foo() 是一个 return 是 T 的表达式,那么 S{}.push(foo()) 可以从 return 的值中省略移动 foo()进入push的论证:只走一步。

但是如果我们S{}.push(std::move(foo()),明确的std::move阻止了省略的可能性。

通常更好的方法是基于放置的操作而不是基于推送的操作。

template<class...Args>
void emplace(Args&&...args) {
  v.emplace_back( std::forward<Args>(args)... );
}

这让您可以将构造 T 的参数传递给对象,并使其直接在接收器(矢量)中构造,而不是移动或复制到其中。

可选:

template<class...Args,
  decltype(T(std::declval<Args&&>()...))* =0
>
void emplace(Args&&...args) {
  v.emplace_back( std::forward<Args>(args)... );
}

如果您需要 SFINAE 支持。评论说 "we expect a T to be constructed here",如果不明显,也是礼貌的。