【问题标题】:something confusing about when should a defaulted move constructor be deleted什么时候应该删除默认的移动构造函数有些令人困惑
【发布时间】:2016-12-29 15:18:54
【问题描述】:
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 中,我定义了 class 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 的复制构造函数。

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

【问题讨论】:

  • 这是core issue 1402
  • 谢谢,现在我明白了,这是C++14带来的某种修改。

标签: c++ constructor default move


【解决方案1】:

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

【讨论】:

  • 因为根据C++ Primer,H的默认移动构造函数应该被定义为delete,结果却显示没有被删除,所以我很惊讶。
  • 谢谢,现在我明白了,这是C++14带来的某种修改
猜你喜欢
  • 2021-12-12
  • 2013-02-01
  • 2019-03-01
  • 2021-09-16
  • 2018-07-01
  • 1970-01-01
  • 2018-07-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多