提问人:Nikesh Subedi 提问时间:9/7/2022 最后编辑:Nikesh Subedi 更新时间:9/7/2022 访问量:57
难以理解 C++ 构造函数和析构函数以及移动/复制语义
Having trouble understanding C++ constructors and destructors and move/copy semantics
问:
我有以下程序,我在其中测试构造函数和析构函数调用的顺序,我对输出感到惊讶。
#include <iostream>
#include <utility>
class Doctor {
public:
Doctor(){
std::cout << "Doctor Creation\n";
}
~Doctor(){
std::cout << "Doctor DeCreation\n";
}
};
class Nurse{
public:
int op = 0;
Nurse(){
std::cout << "Nurse Creation\n";
}
~Nurse(){
std::cout << "Nurse " << op << " DeCreation\n";
}
};
class Hospital{
private:
Doctor doc;
Nurse nurse;
public:
Hospital(){
std::cout << "Hospital Creation\n";
}
~Hospital(){
std::cout << "Hospital DeCreation\n";
}
void operate(){
std::cout << "Hospital Operation\n";
nurse.op++;
std::cout << &this->nurse << " " << nurse.op << "\n";
reset_hospital();
std::cout << &this->nurse << " " << nurse.op << "\n";
}
void reset_hospital(){
std::cout << &this->nurse << " " << nurse.op << "\n";
nurse = std::move(Nurse());
doc = std::move(Doctor());
}
};
int main(){
Hospital hospital;
hospital.operate();
}
https://godbolt.org/z/bf8KbqsTK
输出为:
Doctor Creation
Nurse Creation
Hospital Creation
Hospital Operation
0x7fff2316866c 1
0x7fff2316866c 1
Nurse Creation
Nurse 0 DeCreation
Doctor Creation
Doctor DeCreation
0x7fff2316866c 0
Hospital DeCreation
Nurse 0 DeCreation
Doctor DeCreation
它不应该在 std::move 操作上吗?当前对象被破坏并被新对象替换?还是出于某种原因,是复制而不是移动?Nurse 1 DeCreation
我很困惑。
答:
1赞
JohnFilleau
9/7/2022
#1
答
Nurse 0 DeCreation
而不是因为:Nurse 1 DeCreation
Nurse
没有移动赋值运算符(请参阅下面的说明),Nurse
具有使用的复制分配运算符,并且- 如果有一个隐式定义的移动赋值运算符,这将是微不足道的,并且成员将像 一样作,这不会交换基础成员
Nurse
std::memmove
op
移动语义不保证会发生交换。对于微不足道的可移动成员变量,赋值比交换效率高得多。移动语义不一定保证“moved-from”对象与“moved-to”对象的先前状态相同。移动语义仅(应)保证从中移动的对象处于有效状态。它可以是未指定的。
为什么没有移动分配运算符?
https://en.cppreference.com/w/cpp/language/move_assignment
如果没有为类类型(结构、类或联合)提供用户定义的移动赋值运算符,并且满足以下所有条件:
- 没有用户声明的复制构造函数;
- 没有用户声明的移动构造函数;
- 没有用户声明的复制分配运算符;
- 没有用户声明的析构函数,
然后编译器会将移动赋值运算符声明为其类的内联公共成员,签名为 T&T::operator=(T&&)。
Nurse
具有用户声明的析构函数,因此没有隐式声明的移动分配运算符
Nurse
具有隐式定义的复制分配运算符,并且其成员将被复制。第一个被破坏的对象有 ,所以你看 。Nurse
op = 0
Nurse 0 DecCreation
如果它确实有一个移动分配运算符,该怎么办?
如果未为用户提供,则将具有隐式声明的移动赋值运算符。它也是一个微不足道的移动赋值运算符,它只能保证像使用 .即逐字节复制。~Nurse()
Nurse
std::memmove
评论
nurse = std::move(Nurse());
std::move
Nurse()