浅拷贝和深拷贝

浅拷贝:两个对象所指向的地址是同一个地址

深拷贝:两个对象的值相同,并且他们都有独立的地址

对于C++而言,如果不提供自己写的拷贝构造函数,编译器会生成默认的

1.将目标对象的值逐个拷贝过来

2.如果传递的是指针的话,所拷贝的是指针的值,也就是指向的地址,而不是指向的对象(浅拷贝)

3.在析构函数中释放内存时,其他对象中的指针可能还在指向已经被释放的地址,如果再次调用析构函数,则会delete被释放的资源,导致报错

示例:

#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Person
{
    private:
   		string name{"name"};
    	double *height {nullptr};
    public:
    	string get_name() {return name;};
    	double get_height(){return *height};
   	//构造函数
    Person(string name = "none",double height = 0.0);
    //析构函数
    ~Person();
}
//构造函数
Person::Person(string name,double height)
{
    this->name = name;
    this->height = new double {height};
}
//析构函数
Person::~Person(){
    if (height!=nullptr)
        delete height;
}
int main()
{
    Person Mike {'Mike',175.0};
    Person new_person {Mike};
    return 0;
}

在上述例子中,在Person类中定义的指向Person的height属性的指针,并没有定义自身的拷贝构造函数,因此编译器会默认产生浅拷贝的拷贝构造函数,与以下函数等同:

// 默认构造函数
Person(const Person &source)
{
	this->name = source.name
	this->height = source.height
}

默认拷贝构造函数是以值传递的形式进行的,因此它会把Mike的name属性赋值给new_person的name,把指向Mike的height属性的地址也会传给new_person的地址,因此new_person和Mike两个对象的height属性的地址指向的是同一个地址。而在程序结束是将会执行析构函数释放每个变量的内存,因为在栈上面定义,因此遵循后人先出的规则,先释放new_person的内存,将占有heigt属性的地址释放后继续释放Mike的height属性的地址,因为这两个指针的地址一样,因此,第二次释放时,会导致报错。

解决这个问题的方式可以通过自定义拷贝构造函数:

//声明拷贝构造函数
Person(const Person &source);

//定义拷贝构造函数
Person::Person(const Person &source)
{
	this->name = source.name;
	this->height = new double {*(source.height)};
}

如此就会创建一个新的变量,并将传入的变量的指针解引用后的值传递给函数中,并在堆中申请一块新的地址指向新的变量,因此两个变量都拥有独立的值和地址,这样执行析构函数就不会报错了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值