C++之深拷贝&浅拷贝

什么是拷贝构造函数?
通过拷贝对象的方式创建一个新的对象,拷贝构造函数的参数必须是类对象的引用,也就是将一个对象拷贝给另一个新建的对象(用途,在创建对象的时候,使用同一类之前创建的对象来初始化新创建的对象)

Book(Book &b);//必须是引用的原因是,如果是传值方式将实参传递给形参,中间要经历一个对象的拷贝,对象拷贝由必须调用拷贝构造函数,这样就形成一个死循环,无解

拷贝构造函数第一个参数一定是对象的引用,后面如果有其他参数,要给出默认值,否则就缺省不写

Book(Book &b,price = 5.0);

如果没有显示的声明一个拷贝构造函数,系统会自动为类生成一个拷贝构造函数,自动生成的仅仅将对象的所有成员变量复制给当前创建的对象(浅拷贝)
为了一个类中包含动态分配存储空间的指针类型的成员变量时,就必须为这个类设计一个拷贝构造函数,还要为他添加一个赋值操作符重载函数,重载(=)
为了不让对象发生拷贝行为,我们可以显示声明一个拷贝构造函数,并将其设置为private属性

什么是浅拷贝?
数据成员之间的简单复制,系统默认的拷贝构造函数实现的就是浅拷贝

默认的拷贝构造函数实现对数据成员一一赋值,但是如果类中含有指针类型的数据,这种拷贝只是将指针简单的拷贝,并没有分配新的内存

运算符“=”的重载就是实现浅拷贝的原因,由于对象之间含有指针数据类型,a , b恰好指向同一块内存,就是浅拷贝

当两个对象的指针指向同一块内存时,调用第一个的析构函数会释放一次内存,调用第二个又会把这个释放过的内存再次释放一次
对同一个动态内存释放两次以上结果时未定义的,容易导致内存泄露和程序崩溃。此时就需要深拷贝解决问题

注意:浅拷贝带来问题的本质在于析构函数释放多次堆内存,使用std::shared_ptr,可以完美解决这个问题。

什么是深拷贝?
为赋值对象申请了一个新的内存

当拷贝对象中有其他资源(堆)的引用时,对象另开辟一块新的资源,而不再对拷贝对象有其他资源的引用的指针或引用进行单纯的赋值

为了解决浅拷贝的问题,必须显示的定义拷贝构造函数,不但可以复制数据成员,还可以为对象分配各自的内存空间

深拷贝不仅对指针进行拷贝,对指针指向的内容也拷贝,也就是给对象新分配了一块内存,经过深拷贝后的指针是指向不同地址

对于普通成员的赋值,深拷贝浅拷贝都是一样的。

参见C++ primer第5版P448页

/* 深拷贝浅拷贝 */
#include<iostream>

using namespace std;

class A
{
public:
    A(int x) : data(x){}//构造函数初始化
    A(){}
public:
    int data;
};

class B
{
public:
    B(int x) : num(x){data = new int[num];}//构造函数初始化

    B(){};

    B(const B &X) : num(X.num){data = new int[num];}//深拷贝,增加了这一句拷贝构造函数,程序就不会崩溃

    ~B() {delete [] data;}
public:
    int *data;
    int num;
};



int main()
{
    A a(5);//用5初始化
    A b = a;//数据成员之间的赋值
    cout<< b.data<< endl;//输出为5
    cout<< a.data<< endl;//输出为5

    B c(5);//用5初始化
    B d = c;//对象拷贝,数据成员之间的赋值
    cout<< c.data<< endl;//输出为0x7ff5b9402a40
    cout<< d.data<< endl;//输出为0x7ff5b9402a40   指向了同一块内存,调用析构函数的时候造成内存泄露
    return 0;
}
C中的深拷贝浅拷贝是两种不同的对象拷贝方式。 浅拷贝是指将一个对象的值复制到另一个对象,但只复制对象的引用而不复制实际的数据。这意味着当原始对象或新对象的值发生更改时,两者都会受到影响。浅拷贝通常使用指针进行操作。 深拷贝是指将一个对象的值复制到另一个对象,并且同时复制实际的数据。这意味着当原始对象或新对象的值发生更改时,它们是相互独立的,互不影响。深拷贝通常需要手动编写代码来复制数据。 下面是一个示例来说明浅拷贝深拷贝的区别: ```c #include <stdio.h> #include <string.h> typedef struct { char* name; int age; } Person; int main() { // 创建原始对象 Person person1; person1.name = "Alice"; person1.age = 25; // 浅拷贝 Person person2; person2 = person1; // 修改拷贝后的对象 person2.name = "Bob"; person2.age = 30; // 原始对象也会受到影响 printf("person1: name=%s, age=%d\n", person1.name, person1.age); // 输出: person1: name=Bob, age=30 // 深拷贝 Person person3; person3.name = strdup(person1.name); // 手动复制字符串数据 person3.age = person1.age; // 修改拷贝后的对象 person3.name = "Charlie"; person3.age = 35; // 原始对象不受影响 printf("person1: name=%s, age=%d\n", person1.name, person1.age); // 输出: person1: name=Bob, age=30 // 释放内存 free(person3.name); return 0; } ``` 在上面的示例中,我们创建了一个名为`Person`的结构体,其中包含了`name`和`age`两个字段。我们使用浅拷贝将原始对象`person1`复制到新对象`person2`,然后修改了新对象的值,发现原始对象也发生了改变。这是因为浅拷贝只复制了引用,所以两个对象指向同一个内存地址。接下来,我们使用深拷贝将原始对象`person1`复制到新对象`person3`,我们手动复制了字符串数据,并将其值修改后发现原始对象不受影响。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值