空自定义移动构造函数下B类成员地址输出异常的技术疑问
理解移动构造函数行为的常见误区
你的问题核心是对std::move和移动构造函数的职责存在误解,我们一步步拆解:
1. std::move不会自动修改源对象
std::move(obj1)的作用仅仅是将左值obj1转换为右值引用类型,让编译器可以匹配到移动构造函数,但它不会对obj1的成员做任何修改。
你的B类移动构造函数是空的(标记Doubt 1的位置),所以当执行B obj2 = std::move(obj1);时:
obj1的所有成员完全保持原来的状态,它的mp_Val依然指向之前创建的Temp对象(地址0xd48030),自然不会变成nullptr(也就是你预期的0)。
2. 空移动构造函数会导致目标对象成员未初始化
C++中,如果类的成员变量在构造函数中没有被显式初始化,那么它会保留未定义的垃圾值。
你的B移动构造函数没有给obj2.mp_Val赋值,所以obj2.mp_Val的地址0x400880是随机的垃圾内存地址,这也是为什么你看不到Temp默认构造函数的调用——因为obj2.mp_Val根本没有被初始化为任何Temp对象的指针,既没有新创建Temp,也没有从obj1转移指针。
3. 正确的移动构造函数应该怎么写?
移动构造函数的职责是转移源对象的资源,并将源对象置为安全的空状态,避免后续操作(比如析构)导致double free。修改你的B移动构造函数如下:
B(B&& in){ std::cout << "Class B MOVE CTOR" << std::endl; // 转移源对象的资源 mp_Val = in.mp_Val; // 将源对象置为空,防止后续操作访问无效资源 in.mp_Val = nullptr; }
修改后再运行,你会看到:
obj1.mp_Val的输出变成0(nullptr)obj2.mp_Val的地址和原来obj1的地址一致- 全程不会调用任何
Temp的构造函数,因为我们只是转移了指针所有权,没有创建新的Temp对象
总结
移动语义不是自动生效的,它完全依赖你编写的移动构造/赋值函数的逻辑:
- 空的移动构造函数什么都不会做,目标对象成员未初始化,源对象状态不变
std::move只是类型转换工具,不负责资源转移或清空源对象
内容的提问来源于stack exchange,提问作者Upayan
相关产品推荐
相关产品推荐

