在尝试进行复制省略时,我遇到了这种奇怪的行为:
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;
}
GCC和Clang接受此代码,并且都能在两种情况下使用复制省略。
在f1()
中,MSVC会抱怨无法返回o
,因为Obj
的移动构造函数被删除。然而,我希望它能够退回到复制构造函数上。这是MSVC的一个bug还是期望的行为(我不理解),GCC / Clang太宽松了?
如果我提供一个移动构造函数,则MSVC能够在编译时省略移动操作,例如在Release模式下。
有趣的是,MSVC能够编译f2()
。据我所知,这是由于构造函数调用结果的强制复制省略。但是,如果我想要返回o
,就只能手动复制它,这感觉很违反直觉。
我知道这种情况可能对实际应用程序不相关,因为可复制对象通常也是可移动的,但我对其中的机制很感兴趣。
这里是用于测试的在线示例:https://godbolt.org/z/sznds7
delete
函数参与重载决议,但对于特殊成员函数似乎有一个例外,在这种情况下它们被明确忽略。看起来像是MSVC的一个错误。 - cigien= default
)... - davidbakstruct B
的移动构造函数是= default
,但它被“定义”为删除,因为struct B
包含一个成员,该成员是一个具有已删除(= delete
)移动构造函数的结构体... - davidbak