Dev*_*all 23 c++ visual-c++ language-lawyer copy-elision c++17
在摆弄复制省略时,我遇到了这种奇怪的行为:
class Obj {
public:
Obj() = default;
Obj(Obj&&) = delete;
Obj(const Obj&) { std::cout << "Copy" << std::endl; }
};
Obj f1() {
Obj o;
return o; // error C2280: move constructor is deleted
}
Obj f2() {
Obj o;
return Obj(o); // this however works fine
}
int main() {
Obj p = f1();
Obj q = f2();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
GCC 和 Clang 接受此代码并且能够在两种情况下使用复制省略。
在f1()MSVC 中抱怨它无法返回,o因为Obj删除了 的移动构造函数。但是,我希望它能够依靠复制构造函数。这是 MSVC 中的错误还是这种期望的行为(我不明白)和 GCC/Clang 是否过于宽容?
如果我提供移动构造函数,MSVC 能够在编译为Release时省略移动。
有趣的是 MSVC 能够编译f2(). 据我所知,这是由于返回构造函数调用的结果时强制复制省略。但是,o如果我手动复制它,我只能按值返回,这感觉有违直觉。
我知道这种情况可能与实际使用无关,因为可复制对象通常也是可移动的,但我对底层机制感兴趣。
这是用于测试的在线示例:https : //godbolt.org/z/sznds7
How*_*ant 25
缺少错误f1()是 clang 和 gcc 中的一个错误。 它固定在clang的后备箱中。
f1() 不符合强制复制省略的条件。
删除的函数参与重载决议。如果它们被选为最佳重载,则程序格式错误。在 中f1(),被删除的移动构造函数由重载决议选择。
在 中f2(),从 C++17 开始,复制/移动省略是有保证的,因此移动/复制构造函数上的重载解析没有完成。在 C++11/14 中,f2()也是一个错误(与 相同的错误f1()),因为不能保证复制/移动省略。
另请参阅此指南:永远不要删除特殊移动成员,这无可否认是在 C++17 之前编写的。
pro*_*-fh 12
哦,我感到很惭愧,我刚刚意识到另一个答案是霍华德·辛南特(Howard Hinnant),他的著作让我明白了我在这里痛苦地试图解释的内容,这有点荒谬......
由于复制和移动构造函数都已声明,因此它们都存在。尤其是在这里,您小心地定义了自己的复制构造函数;如果没有它,它将被定义为删除(请参阅本演示文稿的第 28 页)。
该删除的方面是关于定义只是细节,但它们都实际上宣告然后资格重载决议。在f1()如果发生了复制省略,那么就没有必要复制和移动构造之间作出选择; 这些都没有使用。另一方面,如果没有发生复制省略,则必须选择最佳重载来构造结果;这里是移动构造函数,因为它存在(它被声明,见这里),最后发现定义被删除,但为时已晚,选择已经做出。
在 中f2(),显式请求显式复制,则复制构造函数是最佳选择。
令人困惑的是,当我们阅读时,=delete我们认为“这不能在重载决议中选择”,但这是错误的;=delete仅在重载决议之后才考虑在找到更好的匹配时为时已晚。
| 归档时间: |
|
| 查看次数: |
904 次 |
| 最近记录: |