C++深拷贝\浅拷贝

C++ 中的深拷贝(Deep Copy)和浅拷贝(Shallow Copy)是指在对象复制时,对象成员的复制方式不同。理解这两种拷贝构造方式非常重要,尤其是在涉及到动态内存分配和资源管理时。

浅拷贝(Shallow Copy)

浅拷贝是指在拷贝对象时,只复制对象的,但对于指针类型的成员变量,拷贝的是指针的地址,即两个对象的指针成员指向同一块内存区域。

浅拷贝的特点:
  • 复制对象的值,包括原始数据的成员。
  • 对于指针成员,只复制指针的值(地址),导致两个对象的指针指向同一块内存。
  • 这种方式可能会导致资源的共享和管理上的问题,尤其是在对象销毁时,如果多个对象指向同一块内存,可能会发生“双重释放”错误。
浅拷贝示例:
#include <iostream>
using namespace std;

class Student {
public:
    int num;
    int *age;  // 指针成员,假设它指向动态分配的内存

    // 构造函数
    Student(int n, int a) {
        num = n;
        age = new int;  // 动态分配内存
        *age = a;
    }

    // 浅拷贝构造函数
    Student(const Student &other) {
        num = other.num;
        age = other.age;  // 只是拷贝指针的值(地址),没有进行深拷贝
    }

    // 析构函数
    ~Student() {
        delete age;  // 释放内存
    }
};

int main() {
    Student s1(1001, 20);
    Student s2 = s1;  // 调用浅拷贝构造函数

    cout << "s1: " << s1.num << ", " << *s1.age << endl;
    cout << "s2: " << s2.num << ", " << *s2.age << endl;

    // s1和s2的age指针指向同一块内存区域
    // 修改s1的age的值会影响s2的age,因为它们共享同一内存

    *s1.age = 25;
    cout << "After modifying s1.age:" << endl;
    cout << "s1: " << s1.num << ", " << *s1.age << endl;
    cout << "s2: " << s2.num << ", " << *s2.age << endl;

    // 程序结束时,s1和s2的析构函数都会被调用,导致删除同一块内存
}
结果:
s1: 1001, 20
s2: 1001, 20
After modifying s1.age:
s1: 1001, 25
s2: 1001, 25

问题

  • s1s2age 指针指向同一块内存,因此修改一个对象的 age 会影响另一个对象。
  • 当程序结束时,两个对象都调用析构函数,释放同一块内存(发生双重释放错误)。

深拷贝(Deep Copy)

深拷贝是指在拷贝对象时,除了复制值之外,还会对指针类型成员指向的内存进行复制。每个对象会有自己独立的内存,不会出现共享资源的问题。

深拷贝的特点:
  • 对象成员的所有值都会被复制。
  • 对于指针成员,会重新分配内存并复制数据,确保每个对象都有自己的内存。
  • 不会发生资源共享问题,因此避免了“双重释放”的错误。
深拷贝示例:
#include <iostream>
using namespace std;

class Student {
public:
    int num;
    int *age;  // 指针成员

    // 构造函数
    Student(int n, int a) {
        num = n;
        age = new int;  // 动态分配内存
        *age = a;
    }

    // 深拷贝构造函数
    Student(const Student &other) {
        num = other.num;
        age = new int;  // 为指针成员重新分配内存
        *age = *(other.age);  // 复制数据,而不是指针地址
    }

    // 析构函数
    ~Student() {
        delete age;  // 释放内存
    }
};

int main() {
    Student s1(1001, 20);
    Student s2 = s1;  // 调用深拷贝构造函数

    cout << "s1: " << s1.num << ", " << *s1.age << endl;
    cout << "s2: " << s2.num << ", " << *s2.age << endl;

    // s1和s2的age指针指向不同的内存区域
    // 修改s1的age的值不会影响s2

    *s1.age = 25;
    cout << "After modifying s1.age:" << endl;
    cout << "s1: " << s1.num << ", " << *s1.age << endl;
    cout << "s2: " << s2.num << ", " << *s2.age << endl;
}
结果:
s1: 1001, 20
s2: 1001, 20
After modifying s1.age:
s1: 1001, 25
s2: 1001, 20

解释

  • s1s2age 指针指向不同的内存区域,因此修改 s1age 不会影响 s2
  • 由于使用深拷贝,s1s2 在析构时会分别释放各自的内存,不会发生双重释放问题。

总结:

  • 浅拷贝:只复制对象的值,对于指针成员,复制的是指针的地址,导致多个对象共享相同的内存。
  • 深拷贝:复制对象的值,对于指针成员,重新分配内存并复制数据,确保每个对象有独立的内存,避免了资源共享的问题。

自定义拷贝构造函数

为了避免浅拷贝带来的问题,特别是当对象中有动态分配的内存时,通常需要自己定义深拷贝构造函数。同时,还需要实现赋值操作符重载,以确保在对象赋值时,拷贝也是深拷贝。

class Student {
public:
    int num;
    int *age;

    Student(int n, int a) {
        num = n;
        age = new int;
        *age = a;
    }

    // 深拷贝构造函数
    Student(const Student &other) {
        num = other.num;
        age = new int;
        *age = *(other.age);
    }

    // 赋值操作符重载(深拷贝)
    Student& operator=(const Student &other) {
        if (this != &other) {  // 防止自赋值
            num = other.num;
            delete age;  // 释放旧的内存
            age = new int;  // 分配新内存
            *age = *(other.age);
        }
        return *this;
    }

    ~Student() {
        delete age;  // 释放内存
    }
};

这样,无论是通过拷贝构造函数还是赋值操作符,都能确保每个对象都拥有自己独立的内存,避免了资源管理的冲突和双重释放问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值