删除移动构造函数并从右值构造对象

Mik*_*ney 3 c++ move move-semantics c++11

我正在尝试理解“Effective Modern C++”中有关特殊成员函数生成的第 17 条,因此我尝试了一些示例并尝试推理某些行为。书中写道:

\n\n
\n

..当我提到移动操作移动构造或移动分配数据成员或基类时,不能保证移动实际上会发生。\xe2\x80\x9c成员移动\xe2\x80\x9d 实际上更像是成员移动请求,因为\xe2\x80\x99t 移动启用的类型(即不为移动操作提供特殊支持,例如,大多数 C++98 遗留类)将通过其复制操作\xe2\x80\x9cmoved\xe2\x80\x9d。\n ...\n 此外,不会为任何生成\xe2\x80\x99d 移动操作显式声明复制操作的类。

\n
\n\n

如果我显式删除移动构造函数,则下面的代码会出错,但如果我不这样做,则对象“s1”将被复制构造而不会出现任何错误。这是指向相同代码的 wandbox 链接:wandbox link。我想我不明白删除移动构造函数和不定义移动构造函数之间的区别。

\n\n
#include <iostream>\n\nstruct S\n{\n    S() = default;\n    S(const S&) {\n        std::cout << "Copying" << std::endl;\n    }\n   // S(S&&) = delete;\n};\n\nS return_lvalue() {\n    S ret{};\n    return ret;\n}\n\nint main() {\n    std::cout << "Hello world" << std::endl;\n    // Error here if I delete move constructor\n    S s1 = return_lvalue();\n}\n
Run Code Online (Sandbox Code Playgroud)\n

Nat*_*ica 5

我想我不明白删除移动构造函数和不定义移动构造函数之间的区别。

当你这样做时

struct S
{
    S() = default;
    S(const S&) {
        std::cout << "Copying" << std::endl;
    }
};
Run Code Online (Sandbox Code Playgroud)

编译器不会生成移动构造函数。如果您尝试移动它,重载解析只会找到S(const S&)并且您将获得一个副本。和

struct S
{
    S() = default;
    S(const S&) {
        std::cout << "Copying" << std::endl;
    }
    S(S&&) = delete;
};
Run Code Online (Sandbox Code Playgroud)

当您移动 类型的对象时S,重载解析会找到S(const S&)和 ,S(S&&)但它会选择 ,S(S&&)因为它是更好的匹配。然后它发现它已被删除并且您收到错误。

您需要记住的是删除的构造函数不会将它们从类中删除。它声明它们并使它们可用于重载决议,并且只有在重载决议发生后,它才会检查它们是否被删除。