返回本地对象是否需要移动语义
Does returning a local object require move semantics?
当按值返回本地对象时,C++编译器可以利用移动语义来优化不必要的副本(副本省略)
"可能优化"意味着,如果不满足适当的条件,则行为应返回到基于复制的默认按值返回语义
因此,据我所知,按值返回可复制对象总是有效的。
但是编译器(clang和gcc)似乎不同意我的解释,如下面的MWE所示。
class Foo {
public:
Foo();
Foo(const Foo&);
Foo(Foo&&) = delete;
}
Foo f() { return Foo(); } // error: call to explicitly deleted constructor of 'Foo'
Foo g() { Foo a; return a; } // gcc complains, clang is fine
Foo x = g(); // error: call to explicitly deleted constructor of 'A'
Q1:按价值退货是否要求物品是可移动的
Q2:如果没有,是gcc和clang在我的MWE上表现不好,还是我错过了其他东西?
您只是满足了重载解析的预期行为:Foo()
是一个右值,因此重载解析会发现构造函数Foo(Foo&&)
是最佳匹配。由于该重载已被删除,因此您的程序格式不正确。此外,还有一个特殊的规则,即Foo a; return a;
也将执行过载解析,就好像a
首先是一个右值一样。(该规则基本上适用于返回语句符合副本省略条件的情况。)
这一切都按预期进行。是你删除了超载,所以你明确要求禁止这种建筑。
请注意,"真实"代码通常不会遇到这个障碍,因为一旦您声明了一个复制构造函数,您的类就不会有任何移动构造函数。但你特意说,"不,实际上我确实想要一个move构造函数,如果有人试图使用它,我希望它是一个错误"。
关于此:
Foo g() { Foo a; return a; } // gcc complains, clang is fine
GCC是对的,这不应该编译,因为[class.copy]/32
(强调矿):
当满足省略复制/移动操作的条件,但不满足异常声明的条件时,并且要复制的对象由左值指定,或者当
return
语句中的表达式为(可能带括号)id表达式,该表达式命名具有在正文中声明的自动存储持续时间的对象,或最里面的封闭函数或lambda表达式的参数声明子句,重载解析为副本选择构造函数首先执行,就好像对象是由右值指定的一样。如果第一个过载解析失败或未执行,或者如果所选的第一个参数的类型构造函数不是对对象类型的右值引用(可能是cv限定的),重载解析是再次执行,将对象视为左值。[注意:此两阶段过载解决方案必须执行,而不管是否会发生复制省略。如果省略,它将确定要调用的构造函数不执行,并且即使取消调用,所选构造函数也必须是可访问的--结束音符]
因此,实现应该选择move构造函数进行省略,因为它被删除了,所以程序格式不正确。
- 何时在引用或唯一指针上使用移动语义
- 如何从具有移动语义的类对象中生成共享指针
- 可以使用移动语义更改或改进此C++代码吗?
- c++在使用指针时移动语义
- 移动语义和深层/浅层复制之间有什么关系?
- std::unique_lock移动语义
- 移动语义和运算符 + 重载
- C++ 移动语义是否在任何情况下都能节省资源?
- 移动语义在这里如何工作?
- 使用移动语义:右值引用作为方法参数
- 在C++中使用移动语义的正确方法是什么?
- 移动语义 c++ 单链表
- C++:使用整数移动语义
- 当变量和参数名称匹配时,移动语义构造失败
- 在 C++11 中移动语义
- 方法冗余移动调用的移动语义
- 复制省略并在返回值中移动语义
- std::元组和移动语义
- 移动语义与返回shared_ptr?
- C++具有移动语义的可变参数工厂会导致运行时崩溃