题目

编写程序,手写一个包含裸指针堆内存缓冲区(int* data_)的动态数组类 IntBuffer。模拟初学者未实现拷贝构造函数时,编译器默认合成的浅拷贝(Shallow Copy)导致的双重释放(Double Free)与悬垂指针内存崩溃;随后完整实现深拷贝(Deep Copy)构造函数,开辟独立堆内存并复制数据,保证每个对象的内存独立性。

输入格式:无需外部输入。

输出格式:输出深拷贝开辟的独立堆内存地址比对与析构日志。

数据范围与约定:内存双重释放防御、指针别名与深拷贝实现。

思路与算法

1. 默认浅拷贝的致命后果
编译器默认生成的拷贝构造函数仅仅对结构体逐字节逐成员按值拷贝(位拷贝 Bitwise copy)。若类中包含 data_ 堆指针,两个对象将指向同一块堆内存。当第一个对象析构 delete[] data_ 后,第二个对象析构时会再次 delete[] data_,直接引发操作系统段错误 free(): double free detected。

2. 深拷贝的实现准则
必须开辟属于当前新对象的独立堆空间:data_ = new int[capacity_];,然后将源对象缓冲区中的每个元素逐一拷贝到新空间中。

3. 自增标识追踪
给每个实例分配一个唯一的自增 id,在构造、拷贝与析构函数中打印指针地址与 id,能直观排查内存生命周期。

完整程序

#include <iostream>
#include <string>

class IntBuffer {
private:
    int* data_;
    size_t size_;
    int id_;
    static int counter;

public:
    IntBuffer(size_t size, int initVal) : size_(size), id_(++counter) {
        data_ = new int[size_];
        for (size_t i = 0; i < size_; ++i) data_[i] = initVal;
        std::cout << "[构造 #" << id_ << "] 已开辟独立堆缓冲, 元素数: " << size_ << "\n";
    }

    // 核心:实现深拷贝构造函数,杜绝浅拷贝指针别名
    IntBuffer(const IntBuffer& other) : size_(other.size_), id_(++counter) {
        data_ = new int[size_]; // 1. 申请属于自己的新堆内存
        for (size_t i = 0; i < size_; ++i) {
            data_[i] = other.data_[i]; // 2. 拷贝实际数据
        }
        std::cout << "[深拷贝构造 #" << id_ << " 来自 #" << other.id_ 
                  << "] 新缓冲与源缓冲同址: " << std::boolalpha << (data_ == other.data_) << "\n";
    }

    ~IntBuffer() {
        std::cout << "[析构函数 #" << id_ << "] 释放堆缓冲\n";
        delete[] data_;
        data_ = nullptr;
    }

    void set(size_t index, int val) {
        if (index < size_) data_[index] = val;
    }

    void print(const std::string& name) const {
        std::cout << name << " (#" << id_ << ") 首元素值: " << data_[0] << "\n";
    }
};

int IntBuffer::counter = 0;

int main() {
    std::cout << "--- 1. 创建原始对象 buf1 ---\n";
    IntBuffer buf1(5, 100);

    std::cout << "\n--- 2. 通过深拷贝创建 buf2 ---\n";
    IntBuffer buf2 = buf1; // 触发深拷贝构造

    std::cout << "\n--- 3. 验证内存隔离性 ---\n";
    buf2.set(0, 999); // 修改 buf2
    buf1.print("buf1");
    buf2.print("buf2");

    std::cout << "\n--- 4. 离开作用域各自独立析构释放 ---\n";
    return 0;
}

运行示例

输出:

--- 1. 创建原始对象 buf1 ---
[构造 #1] 已开辟独立堆缓冲, 元素数: 5

--- 2. 通过深拷贝创建 buf2 ---
[深拷贝构造 #2 来自 #1] 新缓冲与源缓冲同址: false

--- 3. 验证内存隔离性 ---
buf1 (#1) 首元素值: 100
buf2 (#2) 首元素值: 999

--- 4. 离开作用域各自独立析构释放 ---
[析构函数 #2] 释放堆缓冲
[析构函数 #1] 释放堆缓冲