何时应删除默认的移动构造函数时令人困惑的事情
something confusing about when should a defaulted move constructor be deleted
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
的复制构造函数。这就是为什么您会看到打印输出。
相关文章:
- 我什么时候会默认(而不是删除)基类中的复制和移动操作
- 注意:"Entity_c::Entity_c(const Entity_c&)"被隐式删除,因为默认定义格式不正确:
- 删除显式默认函数声明时的警告
- 删除使数据处于"错误状态"的默认构造函数的模式?
- 为什么删除默认构造函数 A::A() 时会编译"A a{};"?
- 为什么这不是"调用隐式删除的'QQmlElement'的默认构造函数"中的默认构造函数
- 默认移动成员定义为已删除,而未定义特殊成员?
- 删除复制构造函数是否也会删除默认的复制/移动运算符?
- 是否可以默认初始化具有已删除默认构造函数的类类型
- 为什么删除默认参数会破坏此 constexpr 计数器?
- 如果构造函数被显式默认或删除,为什么聚合初始化自 C++20 以来不再起作用
- 为什么在派生类中删除默认构造函数
- 删除默认类构造函数有什么意义?
- 有条件地实例化具有删除默认构造函数的类
- 何时应删除默认的移动构造函数时令人困惑的事情
- 删除默认C++复制和移动构造函数和赋值运算符的缺点
- 为什么可以删除任何函数,而只能删除默认的特殊成员函数
- 已删除默认构造函数.仍然可以创建对象..有时
- 了解Lambda闭包类型如何删除默认构造函数
- 使用boost program_options处理帮助消息,删除默认值或重新格式化帮助消息