在 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_a
和my_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<std::vector<double>, std::vector<double>> r;\nauto& [my_vec_a, my_vec_b] = r; \n//do something\nreturn r;
以上是关于在 return 语句中移动构造函数中的语义的主要内容,如果未能解决你的问题,请参考以下文章
是否可以在 C++ 中将返回值移动语义与受保护的复制构造函数一起使用?