移动省略优化

Move elision optimization

本文关键字:优化 移动省      更新时间:2023-10-16

考虑一个类的两个实现:

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)?现代编译器能优化掉不必要的动作吗?或者这是标准所禁止的?

否,该省略是不合法的,除了under if优化之外。

现在,如果foo()是一个返回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)... );
}

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

可选:

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

如果您想要SFINAE支持。一条评论说"我们希望在这里构建一个T",如果不明显的话,也是礼貌的。