You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:08:35