拷贝构造函数中的浅拷贝与深拷贝

拷贝构造函数, 编译器 调用来完成一些基于同一类的其他对象的构建及初始化。

1.构造函数调用规则

构造函数调用规则如下:

默认情况下,c++编译器至少给一个类添加3个函数

  1. 默认构造参数(无参,函数体为空)
  2. 默认析构参数(无参,函数体为空)
  3. 默认拷贝构造函数,对属性进行值拷贝
  • 如果用户定义有参构造函数,c++不再提供默认无参构造,但是回提供默认拷贝构造
  • 如果用户定义拷贝构造函数,c++不会再提供其他构造函数

(自己写的高级构造函数会屏蔽编译器提供的低级构造函数)

2.浅拷贝与深拷贝

  • 浅拷贝:简单的赋值操作
  • 深拷贝:在堆区中重新申请空间,进行拷贝操作

案例:发生在默认拷贝构造函数中的浅拷贝 

#include<iostream>
using namespace std;

class person
{
public:
    person()
    {
        m_age = 0;
        cout << "person的默认构造函数"<<endl;
    }
    person(int age,int height)
    {
        m_age = age;
        cout << "person的有参构造函数调用" <<m_age<< endl;

        m_height = new int(height);//为形参height在堆区中new出一个地址,用指针接收
    }
    ~person()
    {
        cout << "person的析构函数调用" << endl;
    }
    int m_age;
    int* m_height = NULL;
};
void test01()
{
    person p1(18,160);
    cout << "p1的年龄为: " << p1.m_age <<"p1的身高为: "<<p1.m_height<< endl;

    person p2(p1);//没有自定义的拷贝构造函数,则为默认拷贝函数
    cout << "p2的年龄为: " << p2.m_age << "p2的身高为: " << p2.m_height << endl;
    //输出 p1 和 p2 身高的地址
}
int main() {

    test01();
    system("pause");
    return 0;
}

运行结果如下图:

 注意 :我们自己只声明了构造函数和析构函数,并没有声明拷贝函数,则使用了默认的拷贝函数

然后这里发现p1p2的身高的地址是相同的,说明两个指针 p1.m_height p2.m_height 指向了同一处地方的数据。

接下来,修改完善一下析构函数(添加  释放new出的在堆区中的内存  的操作)

~person()
    {
        //析构代码,将堆区开辟的数据做释放操作
        if (m_height != NULL)
        {
            delete m_height;
            m_height = NULL;
        }
        cout << "person的析构函数调用" << endl;
    }

然后运行结果如下图:

此时程序已经崩掉了,按道理应该还会打印一个 "person的析构函数调用" 

 原因1.首先我们知道两个指针 p1.m_height p2.m_height 指向了同一处地方的数据(height),

2.当我们调用 test01函数 时,先构造了 类p1,然后拷贝构造 p2,因为 test01函数 是在栈区(后进先出)上运行的,当执行完操作后,程序销毁时就会先调用p2析构函数,将在堆区中存放m_height的内存释放掉,

3.接着,再执行p1的析构函数,重复将在堆区中存放m_height的内存释放掉,问题就出在这里

这就是浅拷贝引发的问题 ,在拷贝构造时,它只是单纯地将new int(height)(即p1.m_height)复制给p2.m_height,最后导致重复delete内存。

解决办法: 利用 深拷贝 解决

自己实现拷贝构造函数(在类person中添加下面函数)  , 解决 浅拷贝 带来的问题

person(const person& p) //传进的p就是p1
    {
        cout << "person 拷贝构造函数调用" << endl;
        m_age = p.m_age;
        //m_height=p.m_height ; 编译器默认实现这行代码(浅拷贝)

        //深拷贝操作:在堆区中新new一块内存存放*p.m_height 
        m_height = new int(*p.m_height); 
        
    }

运行结果如下图:

 可以发现,程序正常运行,且两个地址p1.m_heightp2.m_height 不同,其中存放的数据都是160

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值