关于C++构造/析构函数及移动语义的运行结果疑问
问题:为什么std::move操作未触发预期的"Nurse 1 DeCreation"?
我编写了一段测试C++构造函数、析构函数调用顺序的程序,运行后输出与预期不符。执行std::move操作时,我预期会出现"Nurse 1 DeCreation",但实际输出"Nurse 0 DeCreation",不确定当前对象是否被销毁替换,或是误执行了复制而非移动操作。
测试代码
#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(); }
程序输出结果
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
解答
核心原因
nurse = std::move(Nurse())执行的是移动赋值操作,而非销毁原对象后创建新对象。原hospital中的nurse对象内存地址全程未变(从输出的地址可以验证),它不会被销毁,只是被临时对象的内容移动覆盖。
详细执行步骤拆解
- 临时对象创建:
Nurse()会创建一个临时Nurse对象,此时输出"Nurse Creation",这个临时对象的op初始值为0。 - 移动赋值触发:
std::move()将临时对象转换为右值引用,触发编译器生成的默认移动赋值运算符。默认移动赋值会把临时对象的op值(0)拷贝给原nurse对象的op,覆盖原本的1。 - 临时对象销毁:临时对象完成移动赋值后生命周期结束,触发析构函数,输出"Nurse 0 DeCreation"——这条输出销毁的是临时对象,而非
hospital中的原nurse对象。 - 原对象的最终销毁:
hospital中的nurse对象直到main函数结束、hospital对象生命周期终止时才会被析构,此时它的op已经被修改为0,所以最后输出"Nurse 0 DeCreation"。
额外说明
- 关于
Doctor的操作逻辑完全一致:doc = std::move(Doctor())创建临时Doctor对象,执行默认移动赋值(因为Doctor没有自定义成员,实际无操作),临时对象销毁输出"Doctor DeCreation",原doc对象直到最后才被销毁。 - 这里没有执行复制操作,确实是移动赋值,但对于
int这种简单类型,默认移动赋值和复制赋值的行为一致,都是值拷贝。 - 原对象(
hospital中的nurse和doc)从未被销毁替换,它们的内存地址始终不变,只是成员值被临时对象覆盖。
内容的提问来源于stack exchange,提问作者Nikesh Subedi
相关产品推荐
相关产品推荐

