考虑类
Dog
继承自 Animal
:
class Animal { … };
class Dog: public Animal {
public:
Dog(Dog&& other)
: Animal(std::move(other)),
breed(std::move(other.breed)) {
}
private:
std::string breed;
};
移动构造函数首先使用
std::move(other)
构造父对象。
然而,标准库说:
[移动操作后,]移出的对象应置于有效但未指定的状态。
如果我理解正确的话,这意味着
other
指向的对象现在处于未指定状态。这意味着构造属性 breed
的下一行将导致未指定的值。
这是正确的吗?
在
Animal(std::move(other))
之后,基类处于由Animal
作者通过他/她设计的Animal
移动构造函数控制的状态。 Animal
的客户不应假设任何特定状态,除非 Animal
的作者已经记录了此类状态。
理论上,
Animal
的作者可以设计Animal
移动构造函数来假设它是Dog
的子对象,并进入Dog
并摆弄数据成员breed
。 这样做是非常不正统的。 Animal
的良好设计通常不会假设诸如从中派生出哪些类之类的事情。
一般来说,假设代码行为良好,基类
Animal
不知道它是由Dog
派生的,并且其移动构造函数不会更改派生类的数据成员。 当然,如果 Animal
的移动构造函数是由编译器提供的,则它不会执行此操作。 编译器提供的移动构造函数仅移动其自己的基址和成员(按该顺序和声明顺序)。
您为
Dog
显示的移动构造函数是普遍接受的正确移动构造函数,并且与编译器提供的移动构造函数相同,即由 Dog(Dog&&) = default;
生成的移动构造函数。