VS2010调试模式下Copy constructor未被调用的技术咨询
问题解答:为什么赋值操作没调用拷贝构造函数,导致悬空指针?
嘿,我来帮你把这个问题掰明白~
核心误区:拷贝构造函数 ≠ 赋值运算符
你混淆了拷贝构造函数和赋值运算符的调用场景:
- 拷贝构造函数仅在对象初始化时被调用,比如:
Inner a = b; // 初始化,调用拷贝构造 Inner a(b); // 同样是初始化,调用拷贝构造 - 而像
myInner = tmpInner;这种已经存在的对象之间的赋值操作,调用的是赋值运算符operator=,不是拷贝构造函数。
你的代码里只自定义了拷贝构造函数,但没有重载赋值运算符,这时候编译器会自动生成一个默认赋值运算符——它的行为是浅拷贝:只会把tmpInner.name的指针值直接复制给myInner.name,不会为myInner重新分配内存、拷贝字符串内容。这就导致两个对象的name指向同一块堆内存,当tmpInner在func()结束时销毁,它的析构函数会释放这块内存,myInner的name就变成了悬空指针,后续访问自然会出现乱码,甚至程序崩溃。
关于你看到的优化现象
你提到的Inner tmpInner = Inner("special");没有打印CopyCtor...,这是因为编译器做了返回值优化(RVO):它直接在tmpInner的内存位置构造临时对象,省略了拷贝构造的步骤。但这和你后面的赋值问题无关——即使关闭这个优化(VS2010可以在项目属性→C/C++→优化→禁用特定优化中选择/Od,或者勾选“消除复制构造函数”的禁用选项),也不会改变赋值操作的行为,因为赋值本来就不会调用拷贝构造。
解决方法:重载赋值运算符,实现深拷贝
要解决这个问题,你需要遵循C++的三法则(当类需要自定义析构函数、拷贝构造函数时,也必须自定义赋值运算符),手动实现赋值运算符的深拷贝逻辑:
class Inner{ public: // 你的其他构造、析构、拷贝构造函数保持不变 Inner& operator=(const Inner& other) { printf("Assignment Operator...\n\r"); // 先处理自赋值的情况,避免重复释放内存 if (this != &other) { // 释放当前对象已有的内存 delete[] this->name; // 重新分配内存并拷贝内容 this->name = new char[strlen(other.name) + 1]; strcpy(this->name, other.name); } return *this; } // ...其他成员 };
加上这个重载后,myInner = tmpInner;就会调用你自定义的赋值运算符,为myInner重新分配内存、拷贝字符串,避免浅拷贝带来的问题。
验证你的程序输出
结合你的输出结果来看:
tmpInner的name地址是0x3864208,赋值给myInner后,myInner.name也指向这个地址tmpInner销毁时释放了0x3864208,所以myInner后续打印时,这个地址的内存已经被释放,出现乱码- 最后
myInner销毁时,又尝试释放一次0x3864208,这属于重复释放内存,是未定义行为
内容的提问来源于stack exchange,提问作者woelfchen42
相关产品推荐
相关产品推荐

