移动省略优化

Ori*_*ent 2 c++ optimization move-semantics perfect-forwarding c++11

考虑一个类的两个实现:

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)); }
};
Run Code Online (Sandbox Code Playgroud)

S1push重载表达正是我想要的.S2push是一种以不那么冗长的方式表达它的方式.

但我担心对象的过度移动构造存在缺陷.

现代编译器可以减少表达std::move(T(std::move(t)))std::move(t)一些t地方decltype(t)T&?现代编译器可以优化不必要的移动吗?或者这是否被标准禁止?

Yak*_*ont 6

不,除了as-if优化之外,这种省略不合法.

现在,如果foo()是一个返回a的表达式T,那么S{}.push(foo())可以忽略从返回值foo()到参数的push移动:只进行一次移动.

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

通常更好的方法是基于动作的操作而不是基于推送的操作.

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

这允许您传递参数以构造T对象,并使其直接构建在接收器(向量)中,而不是移动或复制到其中.

可选:

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

如果你想要SFINAE支持.评论说"我们希望在T这里建造一个",如果不是很明显,也是礼貌的.