当前位置: 首页 > news >正文

C++之深浅拷贝

一、浅拷贝

我们看下以下代码
Test.h 文件

#pragma once
#include<iostream>
using namespace std;
class Student
{
public:Student(){}~Student(){if (m_Id != nullptr){delete m_Id;m_Id = nullptr;}}Student(int id, string strName){m_Id = new int[id];m_strName = strName;}
private:int* m_Id;string m_strName;
};

Test.cpp 文件

#include"Test.h"
int main()
{Student s1(1, "zhangsan");Student s2(s1);cout << "helloworld" << endl;return 0;
}

运行:
在这里插入图片描述
只是简单的构造了两个类对象,最后运行却崩溃了
崩溃点是析构函数

	~Student(){if (m_Id != nullptr){delete m_Id;m_Id = nullptr;}}

那么我们把这段删除掉试一试
在这里插入图片描述
运行:
在这里插入图片描述
ok 问题解决了?这样只会造成内存泄漏,并不是不释放 = 解决问题
但是这不是问题的本质
直接原因:析构函数,多次释放同一块空间,导致崩溃
根本原因:默认拷贝构造函数
是的,类的默认拷贝构造函数

	Student s1(1, "zhangsan");Student s2(s1);

在类 Student 中 并没有定义拷贝构造函数,那么在 Student s2(s1); 时会调用类的默认成员函数:拷贝构造函数
而浅拷贝会导致一个结果

s1->m_Id
s2->m_Id

这两个类对象的成员变量 m_Id 的地址其实是一致的
打印各自的m_Id

	void GetMemberAdd(){cout << m_Id << endl;}
	s1.GetMemberAdd();s2.GetMemberAdd();

结果:
在这里插入图片描述
那么两个类对象调用析构函数,s1 先析构 delete m_Id 接着 s2 再次释放,那么就属于非法操作一块空间,最终导致崩溃。

有些朋友,可能说并没有出现这种情况,是的如果只是值拷贝,不涉及,指针拷贝,引用时深浅拷贝是一样的。
那么当涉及到指针、引用时则需要自己实现拷贝构造函数,实现深拷贝,避免造浅拷贝所出现的问题。
并且建议最好自己实现一下拷贝构造函数与类对象的 “=” 操作符重载
否则也是会出现以下情况
在这里插入图片描述

二、深拷贝

看了上述的问题,那么如何来解决浅拷贝的问题呢,这里就引入深拷贝的问题
我们直到出现问题的原因是:

s1->m_Id Address == s2->m_Id Address

那么我们在拷贝构造函数为每一个新的类对象的都动态创建一个新的 m_Id 那么就可以解决浅拷贝的问题了,看代码

	Student(const Student& s){int iTemp = *(s.m_Id);m_Id = new int(iTemp);//动态申请新的空间,再赋值m_strName = s.m_strName;}

在这里插入图片描述
总结:深拷贝是开辟新的空间,再存储值,使用默认的拷贝构造,会将两个指针指向同一块空间(并没有开辟新的空间) 而是共用一块空间,因此在释放时会导致崩溃。

完整测试代码
Test.h

#pragma once
#include<iostream>
#include<string>
using namespace std;
class Student
{
public:Student(){}~Student(){if (m_Id != nullptr){delete m_Id;m_Id = nullptr;}}Student(int id, string strName){m_Id = new int(id);m_strName = strName;}Student(const Student& s){int iTemp = *(s.m_Id);m_Id = new int(iTemp);m_strName = s.m_strName;}void GetMemberAdd(){cout << m_Id << endl;}void Print(){cout << *m_Id << endl;cout << m_strName << endl;}
private:int* m_Id;string m_strName;
};

Test.cpp

#include"Test.h"
int main()
{Student s1(1, "zhangsan");Student s2(s1);s1.Print();s2.Print();cout << "helloworld" << endl;s1.GetMemberAdd();s2.GetMemberAdd();return 0;
}
http://www.lryc.cn/news/39283.html

相关文章:

  • CoreLocation的一切
  • HashMap原理
  • STM32入门笔记(02):独立看门狗(IWDG)和窗户看门狗(WWDG)(SPL库函数版)
  • javaSE系列之方法与数组的使用
  • 常用命令总结
  • 【Linux:程序地址空间--原来操作系统也喜欢画大饼】
  • Python实现简单信号滤波实战
  • Java(110):非对称加密RSA的使用(KeyPair生成密钥)
  • (Mybatis 学习【1】)整合 Mybatis 开发流程
  • 一文搞懂Kerberos
  • Go爬虫学习笔记(三)
  • CASTEP参数设置(2)
  • 浅谈对Promise的理解以及在工作中的应用
  • 开源|快速入门和理解并模拟实现GPS户外机器人的定位与导航
  • Java多线程系列--synchronized的原理
  • QEMU启动ARM64 Linux内核
  • Linux->进程程序替换
  • 最强分布式锁工具:Redisson
  • Java9-17新特性
  • 电脑开机找不到启动设备怎么办?
  • 使用langchain打造自己的大型语言模型(LLMs)
  • assert()宏函数
  • Docker圣经:大白话说Docker底层原理,6W字实现Docker自由
  • Redis+Caffeine多级(二级)缓存,让访问速度纵享丝滑
  • C#和.net框架之第一弹
  • C++---背包模型---潜水员(每日一道算法2023.3.12)
  • C++类的成员变量和成员函数详解
  • (枚举)(模拟)(位运算)116. 飞行员兄弟
  • 详解Array.prototype.shift.call(arguments)
  • Tina_Linux_Wi-Fi_开发指南