以下 std::move 的情况是多余的吗?

Is the following case of std::move superfluous?

下面的std::move是多余的吗?

std::string member;

obj(std::initializer_list<std::string> p_list)
    : member {std::move(join(p_list))}
{}

这是连接函数:

std::string join(string_initializer_list p_list) {
    size_t size {};
    for (auto const & s : p_list) {
        size += s.size();
    }
    std::string output;
    output.reserve(size);
    for (auto const & s : p_list) {
        output.append(s);
    }
    return output;
}

鉴于您的 join 功能正常,并且 return 和 std::string,是的,std::move 是多余的; join 中的 return 已经是一个 r 值。

除此之外,w/o std::move,复制省略意味着它可以在没有 std::move 的情况下就地构造结果,而使用 std::move 可以强制它生成一个临时的string,调用移动构造函数初始化member,然后销毁临时;工作量不大(主要是几个指针副本),但比您需要做的要多。

不,你不需要 std::movestd::move 的作用是将任意值转换为右值。您的函数已经 return 是一个右值,因此就将结果绑定到引用而言,强制转换没有任何效果(这就是您要从右值初始化 member 所追求的) .

实际上,主动使用std::move抑制了拷贝省略,所以是严格的悲观化:

std::string s = join({});             // construct from prvalue, elidable,
                                      // elision mandatory in C++17

std::string s = std::move(join({}));  // temporary object must be constructed,
                                      // s is initialized by moving from the
                                      // temporary

在第一种形式中,std::string s = join({});,复制省略意味着 join 的 returned 对象直接在 s 的位置构造(没有临时对象是构造并复制或移动),而且,函数体中的output变量也被省略并直接在return值中构造,即在s中。对于 std::move,第一个省略步骤不可用。

为清楚起见:任何按值 returns 并因此 returns 右值的函数都不需要应用 std::move ,正如其他人已经指出的那样,它对性能优化。

例如

SomeClass fn()
{
...
}

// Move not needed, detrimental, as the function result is already an rvalue
SomeClass x = std::move(fn()); 

像往常一样在 c++11 之前这样做:

SomeClass x = fn();

一般来说当x有名字的时候使用std::move(x)。即它是一个标识符,除了特殊情况(例如,你想防止复制省略)外,它对临时对象没有用

旁注:也不要尝试使用 std::move 来强制 "strong exception gurantee"(例如,当你想要一个完全复制或单独保留的结构时 [即一致]潜在的异常。)因为 std::move 可以抛出取决于移动的类型,并且这种类型的异常策略可以根据你改变。而是使用带有静态断言的包装函数与 noexcept 相结合,以在编译时强制执行此操作。参见