在 return 语句中移动构造函数中的语义

Posted

技术标签:

【中文标题】在 return 语句中移动构造函数中的语义【英文标题】:move semantics in constructor in return statement 【发布时间】:2021-12-03 00:48:57 【问题描述】:

我知道当返回一个本地以保持 RVO 时,我们应该允许编译器通过返回这样的值来执行移动省略

std::vector<double> some_func()
    std::vector<double> my_vector;
    //do something
    return my_vector;

而不是

std::vector<double> some_func()
    std::vector<double> my_vector;
    //do something
    return std::move(my_vector);

但是,如果我们在 return 语句中构造一个对象,那么在构造函数中使用 std::move 是否有助于、阻碍或无助于提高效率或妨碍编译器?

以这两种实现为例

std::pair<std::vector<double>,std::vector<double> > some_func()
    std::vector<double> my_vec_a;
    std::vector<double> my_vec_b;
    //do something
    return std::make_pair(my_vec_a,my_vec_b);

std::pair<std::vector<double>,std::vector<double> > some_func()
    std::vector<double> my_vec_a;
    std::vector<double> my_vec_b;
    //do something
    return std::make_pair(std::move(my_vec_a),std::move(my_vec_b));

所以

    首先,编译器会识别出my_vec_amy_vec_b 会超出范围并优化return 语句中的构造吗? 如果是这样,在第二个中使用 std::move 会阻止优化吗? 或者第二个选项会更有效吗?

【问题讨论】:

答案取决于编译器及其优化设置。请注意,即使对于前两个 sn-ps,带有 -O1 的 gcc 11.1 也会产生完全相同的程序集。您可以在浏览器中轻松查看,此处为godbolt.org @DarioP 很酷的网站,谢谢。是的,在优化时,它们都给出了相同的组件。我的主要恐惧是不知何故妨碍了省略。 @user3353819 你怎么认为它提供了相同的程序集?两种编译器都能够更好地针对使用std::move 的情况进行优化。 godbolt.org/z/sa9ocnPvG。根据 cppreference which is of the same class type (ignoring cv-qualification) as the function return type. This variant of copy elision is known as NRVO,NRVO 不适用于这种情况。所以,我更喜欢在这里使用std::move @Staz 啊,我没有将它包装在 foo() 函数中,所以没有看到整个返回的上游优化,所以只是在查看 @ 程序集的变化987654335@。是的,好的,明白了,谢谢。 【参考方案1】:

这个效率更高:

std::pair<std::vector<double>,std::vector<double> > some_func()  
    std::vector<double> my_vec_a;
    std::vector<double> my_vec_b;
    //do something
    return std::make_pair(std::move(my_vec_a),std::move(my_vec_b));

如果不调用std::move,这两个向量将被复制。

然而,问题不在于实际回报。这是正在构造的对中的两个向量是从左值构造的;如果您没有通过std::move 明确告诉它,编译器就无法选择在那里使用移动构造函数。

【讨论】:

还有一个选项:std::pair&lt;std::vector&lt;double&gt;, std::vector&lt;double&gt;&gt; r;\nauto&amp; [my_vec_a, my_vec_b] = r; \n//do something\nreturn r;

以上是关于在 return 语句中移动构造函数中的语义的主要内容,如果未能解决你的问题,请参考以下文章

C++11移动构造函数详解

使用移动语义在构造函数中初始化类成员

是否可以在 C++ 中将返回值移动语义与受保护的复制构造函数一起使用?

如何解释构造函数中的返回语句?

cpp►C++11右值引用移动语义移动构造函数移动赋值运算符

cpp►C++11右值引用移动语义移动构造函数移动赋值运算符