应该删除默认移动构造函数的时候会让人感到困惑

时间:2016-12-29 15:18:55

标签: c++ constructor default move

class N {
public:
    N() = default;
    N(const N& n) { std::cout << "N copy\n"; };
private:
    char c;
};

class H {
public:
    H() = default;
    H(H&) { std::cout << "H copy\n"; }
    H(H&&) = default;
private:
    N n;
};

int main() {
    N n1, n2 = std::move(n1);
    H h1, h2 = std::move(h1);
}

在VS2016中,我定义了类N,看看如果移动构造函数既没有被编译器定义也没有被编译器合成会发生什么。并定义类H以查看删除默认移动构造函数时会发生什么。

在main函数中,执行第一个语句会打印“N copy”,这意味着调用了复制构造函数,因为N中没有移动构造函数。

我无法理解的是,执行第二个语句“h2 = std :: move(h1)”也会打印“N copy”。

正如我在C ++ Primer(它基于C ++ 11)中所读到的那样,如果类具有定义其自己的复制构造函数但未定义的成员,那么类的默认移动构造函数将被定义为已删除移动构造函数。由于成员n满足该条件,因此应删除H的移动构造函数,“h2 = std :: move(h1)”应调用复制构造函数,从而打印“H copy”。

但是,只打印“N copy”,这意味着不调用H的复制构造函数,而是调用N的复制构造函数。为什么呢?

这就是我的猜测:

编译器仍然为H合成了一个移动构造函数,它的工作方式如下:

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

这里移动构造函数尝试移动成员n,就像“N n1,n2 = std :: move(n1);”中发生的那样,调用N的复制构造函数,从而打印出“N copy”

这个解释确实有意义,但是根据C ++ Primer,H的默认移动构造函数应该被定义为delete。它是应该被调用的H的复制构造函数。

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

1 个答案:

答案 0 :(得分:1)

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