何时应删除默认的移动构造函数时令人困惑的事情

something confusing about when should a defaulted move constructor be deleted

本文关键字:删除 默认 移动 构造函数 何时应      更新时间:2023-10-16
class N {
public:
    N() = default;
    N(const N& n) { std::cout << "N copyn"; };
private:
    char c;
};
class H {
public:
    H() = default;
    H(H&) { std::cout << "H copyn"; }
    H(H&&) = default;
private:
    N n;
};
int main() {
    N n1, n2 = std::move(n1);
    H h1, h2 = std::move(h1);
}

在VS2016中,我定义了N类,以查看如果编译器未定义也不合成移动构造函数,会发生什么;并定义h类,以查看如果删除默认的移动构造函数将会发生什么。

在主函数中,执行第一个语句打印" n copy",这意味着复制构造函数之所以称为,是因为n。

中没有移动构造函数。

我无法理解的是,执行第二个语句" H2 = STD :: MOVE(H1)"也打印了" N copy"。

正如我在C 底漆中所读的(基于C 11)一样,如果类有一个定义自己的复制构造函数但未定义的成员,则类的默认移动构造函数将被定义为删除移动构造函数。由于成员n符合该条件,因此应删除H的移动构造函数," H2 = STD :: MOVE(H1)"应调用复制构造函数,从而打印" H COPY"。

但是,仅打印" n副本",这意味着未调用H的复制构造函数,但n的复制构造函数被调用。为什么?


这是我猜:

编译器仍然合成了H的移动构造函数,它的工作原理:

H(H&& h) :n(std::move(h.n)) {}

这里移动构造函数试图移动成员n,就像" n n1,n2 = std :: move"(n1)中发生的事情一样,n的复制构造函数被称为,因此" n copy"被打印。


此解释确实很有意义,但根据C 引物,H的默认移动构造函数应该定义为删除。应该称为H的复制构造函数。

所以我很困惑:这本书错了吗?还是这是新标准引入的一些新属性?还是由编译器引起的?

您感到惊讶吗?您为H有一个默认的移动构造函数,它将调用所有成员的移动或复制构造函数。只有一个成员,类型的N,它没有移动构造函数 - 因此调用了N的复制构造函数。这就是为什么您会看到打印输出。