【C++】深拷贝&浅拷贝

前言:在 C++ 中,当一个对象通过赋值或拷贝即将成为另一个对象的副本时,会发生“浅拷贝”或“深拷贝”。

什么是浅拷贝?

        浅拷贝是指两个对象共享同一个内存地址,即将源对象的数据成员的地址赋给了目标对象,当源对象和目标对象被销毁时,会发生重复释放的问题,导致程序崩溃。

        同一类型的对象之间可以赋值,使得两个对象的成员变量的值相同,两个对象仍然是独立的两个对象,这种情况被称为浅拷贝.

        一般情况下,浅拷贝没有任何副作用,但是当类中有指针,并且指针指向动态分配的内存空间,析构函数做了动态内存释放的处理,会导致内存问题。

 看图理解:

下面是一个浅拷贝的示例:

class Person {
public:
    int mAge;
    char* pName;
    Person(const char* n, int a) : name(new char[strlen(n) + 1]), mAge(a) {
        strcpy(pName, n);
    }

    // 浅拷贝构造函数
    Person(const Person & p) : age(p.mAge), name(p.pName) {} 
};

        在上述代码中,我们定义了一个 Person 类,包含了一个 char 类型的指针成员 pName 和一个 int 类型的成员 mAge。 在浅拷贝的构造函数中,会将源对象的地址直接赋值给目标对象,这样就会导致两个对象共享同一块内存,当其中一个对象被销毁时,会导致另一个对象的指针成员变量指向一块已被释放的内存,从而引发程序崩溃。

什么是深拷贝?

        深拷贝是指在拷贝对象时,会开辟一块新的内存空间来存储数据,并将源对象的数据成员的内容复制到目标对象的数据成员中,这样就不会有重复释放的问题。

        当类中有指针,并且此指针有动态分配空间,析构函数做了释放处理,往往需要自定义拷贝构造函数,自行给指针动态分配空间,深拷贝

看图理解:

下面是一个深拷贝的示例:

class Person {
public:
    int mAge;
    char* pName;
    Person(const char* n, int a) : name(new char[strlen(n) + 1]), mAge(a) {
        strcpy(pName, n);
    }

    // 深拷贝构造函数
    Person(const Person & p) : age(p.mAge), name(new char[strlen(p.pName) + 1]) {
        strcpy(name, p.pName);
    } 
};

        在上述代码中,我们使用深拷贝的方式创建一个对象,将源对象的数据成员的内容复制到了目标对象中,防止了重复释放的问题。

如何选择?

        当对象中只包含了基本数据类型成员时,可以使用浅拷贝;当对象中包含了指针类型成员时,需要使用深拷贝。

        在实践中,我们需要根据具体的情况选择不同的拷贝方式。当对象中存在指针类型成员时,需要确保在拷贝时不会共享同一个地址,否则需要使用深拷贝。此外,在使用深拷贝时,还要注意好释放内存,避免内存泄漏的问题。

        下面以一个包含指针类型成员变量的例子来作为说明:

class Employee {
public:
    Employee(const char* n, int a, const char* p) : name(new char[strlen(n) + 1]), age(a), position(new char[strlen(p) + 1]) {
        strcpy(name, n);
        strcpy(position, p);
    }

    ~Employee() {
        delete[] name;
        delete[] position;
    }

    // 浅拷贝构造函数
    Employee(const Employee& other) : name(other.name), age(other.age), position(other.position) {} 

    // 深拷贝构造函数
    Employee(const Employee& other) : age(other.age), name(new char[strlen(other.name) + 1]), position(new char[strlen(other.position) + 1]) {
        strcpy(name, other.name);
        strcpy(position, other.position);
    }

private:
    char* name;
    int age;
    char* position;
};

        在上述代码中,我们定义了 Employee 类,其中包含了三个成员变量,包括两个 char 类型的指针类型成员变量 name 和 position,以及一个 int 类型的基本数据类型成员变量 age

        我们可以看到,如果要进行浅拷贝,我们只需要将源对象的指针类型成员变量的地址复制给目标对象的指针类型成员变量即可,但是这样做有一个问题就是源对象和目标对象会共享指针指向的内存空间,当源对象被销毁时,目标对象持有的指针就会指向一块已经被释放的内存空间,从而导致程序崩溃,因此浅拷贝对这种类型的成员变量并不适用。

        对于包含指针类型成员变量的对象,常用的拷贝方式是深拷贝。这种拷贝方式会为目标对象重新分配一块内存,并将源对象的数据成员的内容复制到目标对象的数据成员中,从而避免了重复释放的问题。在上述代码中,我们使用了深拷贝的方式来创建目标对象。

总结:

        在 C++ 的开发中,深拷贝和浅拷贝都是很重要的概念,具体应该根据对象的成员变量类型来选择拷贝方式,并且在使用深拷贝时需要注意好内存的释放问题。建议当对象中包含了指针类型成员时,使用深拷贝;当对象中只包含了基本数据类型成员时,可以使用浅拷贝。

回答: 在C++中,深拷贝浅拷贝是两种不同的拷贝方式。浅拷贝是简单的赋值拷贝操作,即将一个对象的值赋给另一个对象。这种拷贝方式只是复制了指针的地址,而没有重新申请内存空间。而深拷贝则是在堆内重新申请空间进行拷贝操作,即重新分配内存并将原对象的值复制到新的内存空间中。\[1\] 浅拷贝可能会带来一些问题,特别是当属性是在堆区开辟的时候。因为浅拷贝只是复制了指针的地址,当原对象和拷贝对象同时指向同一块内存时,如果其中一个对象释放了内存,另一个对象仍然指向已经释放的内存,会导致程序崩溃。为了避免这个问题,我们需要提供自己的拷贝构造函数,进行深拷贝操作,即重新申请内存并复制值。同时,在析构函数中需要释放申请的内存。\[1\] 举个例子来说明深拷贝浅拷贝的区别。假设有一个Student类,其中包含一个指向字符串的指针m_name。在深拷贝中,我们会重新申请一块和原对象的字符串大小相同的内存,并将原对象的字符串复制到新的内存中。而在浅拷贝中,只是简单地复制指针的地址,导致两个对象指向同一块内存。当原对象被销毁时,新对象仍然指向已经释放的内存,可能会导致程序出错。\[2\]\[3\] #### 引用[.reference_title] - *1* [c++深拷贝浅拷贝](https://blog.csdn.net/qq_43611366/article/details/125204856)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [C++深拷贝浅拷贝](https://blog.csdn.net/m0_59052131/article/details/127498856)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SecureCode

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值