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

如何为C++类中的两个指针成员编写深拷贝构造函数?

问题分析与解决方案

老哥,先给你揪出代码里的两个核心问题,再一步步实现正确的深拷贝构造函数:

1. 原构造函数的致命bug

你写的构造函数里藏着两个大坑:

number1 = new float;
number2 = new float;
number1 = &l;
number2 = &w;
  • 你先用new float在堆上分配了内存,但转头就把指针指向了函数参数l和w的栈地址,这直接导致堆内存泄漏——new出来的那块内存再也找不到了,没法释放。
  • 函数参数l和w是栈上的临时变量,构造函数执行完就会被销毁,后续你再访问*number1或*number2,就是在访问已经失效的内存,轻则输出乱码,重则直接崩溃。

正确的构造函数应该把参数的值拷贝到你new出来的堆内存里,两种写法都可以:

abc(float l, float w) {
    // 写法1:new的时候直接初始化值
    number1 = new float(l);
    number2 = new float(w);
    // 写法2:先分配内存再赋值
    // number1 = new float;
    // *number1 = l;
    // number2 = new float;
    // *number2 = w;
}

2. 实现真正的深拷贝构造函数

你当前的拷贝构造函数是浅拷贝,只是把指针的值复制了一遍:

abc(const abc& ob) {
    number1 = ob.number1;
    number2 = ob.number2;
}

这会导致新对象和原对象的指针指向同一块堆内存,一旦其中一个对象被销毁(析构函数释放内存),另一个对象再访问这块内存就会出错;要是两个对象都析构,还会触发重复释放内存的崩溃。

深拷贝的核心就是:给新对象重新分配独立的堆内存,然后把原对象指针指向的值拷贝过去,而不是复制指针本身。

完整修正后的代码

别忘了加析构函数,用来释放堆内存,不然还是会泄漏:

#include <iostream>
using namespace std;

class abc {
    float *number1;
    float *number2;
public:
    // 修正后的构造函数
    abc(float l, float w) {
        number1 = new float(l);
        number2 = new float(w);
    }

    // 深拷贝构造函数
    abc(const abc& ob) {
        // 为新对象分配独立堆内存,同时拷贝原对象的值
        number1 = new float(*ob.number1);
        number2 = new float(*ob.number2);
    }

    // 析构函数:释放堆内存
    ~abc() {
        delete number1;
        delete number2;
    }

    float get_1() {
        return *number1;
    }
    float get_2() {
        return *number2;
    }

    void display() {
        cout << "Number 1 : " << *number1 << endl;
        cout << "Number 2 : " << *number2 << endl;
    }

    // 可选但推荐:重载赋值运算符(遵循Rule of Three)
    abc& operator=(const abc& ob) {
        // 先防止自赋值,不然会把自己的内存释放了再拷贝
        if (this == &ob) {
            return *this;
        }
        // 先释放当前对象的旧内存
        delete number1;
        delete number2;
        // 重新分配内存并拷贝值
        number1 = new float(*ob.number1);
        number2 = new float(*ob.number2);
        return *this;
    }
};

// 测试一下效果
int main() {
    abc obj1(10.5f, 20.3f);
    abc obj2 = obj1; // 调用拷贝构造函数

    obj1.display(); // 输出:Number 1 : 10.5 | Number 2 : 20.3
    obj2.display(); // 和obj1输出一样,但内存是独立的

    // 修改obj1的值,验证深拷贝
    *obj1.number1 = 50.0f; // 这里为了测试直接访问私有成员,实际应该加setter方法
    obj1.display(); // 输出:Number 1 : 50 | Number 2 : 20.3
    obj2.display(); // 还是输出10.5和20.3,说明两个对象完全独立
    return 0;
}

额外提醒:Rule of Three原则

当你的类用到堆内存指针时,一定要遵循Rule of Three:如果你定义了拷贝构造函数、拷贝赋值运算符、析构函数中的任意一个,就必须把另外两个也实现了。这样能彻底避免内存泄漏、重复释放、悬垂指针这些常见问题。

内容的提问来源于stack exchange,提问作者john

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 14:02:47