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

Deleting move constructor and constructing object from rvalue

我正在尝试了解 "Effective Modern C++" 中关于特殊成员函数生成的 项 17,因此我尝试了一些示例并试图推理某些行为。书中说:

..that when I refer to a move operation move-constructing or move-assigning a data member or base class, there is no guarantee that a move will actually take place. “Memberwise moves” are, in reality, more like memberwise move requests, because types that aren’t move-enabled (i.e., that offer no special support for move operations, e.g., most C++98 legacy classes) will be “moved” via their copy operations. ... Furthermore, move operations won’t be generated for any class that explicitly declares a copy operation.

如果我显式删除移动构造函数,下面的代码会出错,但如果我不这样做,对象 "s1" 将得到复制构造而不会出现任何错误。这是相同代码的魔杖盒 link:wandbox link。我想我不明白删除移动构造函数和不定义移动构造函数之间的区别。

#include <iostream>

struct S
{
    S() = default;
    S(const S&) {
        std::cout << "Copying" << std::endl;
    }
   // S(S&&) = delete;
};

S return_lvalue() {
    S ret{};
    return ret;
}

int main() {
    std::cout << "Hello world" << std::endl;
    // Error here if I delete move constructor
    S s1 = return_lvalue();
}

删除特殊成员函数与不声明它不同。等同于声明它然后在使用时强制编译错误。

因此,删除一个 move ctor 并没有太大的好处……除非你出于某种原因也删除了复制 ctor,但根本不声明一个 move ctor。

这与引用没有太大关系,它是说如果你 do 声明一个 move ctor 但不在其中做任何 "movey things"然后最终没有任何有价值的东西真正被移动,这可能与您的用户的期望相反。

我建议你不要申报你的移动构造函数。同样,这与被删除不同。一个不会是 auto-generated 因为你有一个复制 ctor。

在此处查找更多技术信息:

请注意,由于省略,您的程序在两种情况下都可以在 C++17 模式下编译。

I guess I'm not understanding the difference between deleting the move constructor and not defining one.

当你

struct S
{
    S() = default;
    S(const S&) {
        std::cout << "Copying" << std::endl;
    }
};

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

struct S
{
    S() = default;
    S(const S&) {
        std::cout << "Copying" << std::endl;
    }
    S(S&&) = delete;
};

当您移动 S 类型的对象时,重载解析会找到 S(const S&)S(S&&),但它会选择 S(S&&),因为它是更好的匹配。然后它看到它被删除了,你得到一个错误。

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