您现在的位置是:首页 > Javascript
当前栏目
C++之深浅拷贝
2023-04-18 14:11:26 时间
一、浅拷贝
我们看下以下代码
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;
}
相关文章
- 前端面试 【JavaScript】— typeof 是否能正确判断类型?
- 前端面试 【JavaScript】— instanceof 能否判断基本数据类型?
- 前端面试 【JavaScript】— 能不能手动实现一下 instanceof 的功能?
- 前端面试 【JavaScript】— Object.is和=== 有什么区别?
- 前端面试 【JavaScript】— JS中类型转换有哪几种?
- 前端面试 【JavaScript】— == 和 ===有什么区别?
- 前端面试 【JavaScript】— 对象转原始类型是根据什么流程运行的?
- JavaScript 的 parseInt() 函数
- javascript实现两个数字进行组合
- JS监听键盘按键
- 大前端开发中的路由管理之五:Flutter篇
- Javascript的DOM操作
- 在Vue项目中使用WebSocket技术
- 新手向:前端程序员必学基本技能——调试JS代码
- React 毁了 Web 开发!
- 「JS 逆向百例」cnki 学术翻译 AES 加密分析
- 商标注册域名后缀用什么?商标和域名有哪些区别?
- 网站建设流程是怎样的?需要看重哪些细节?
- 网站域名商标注册流程是什么?网站域名商标有什么用?
- 如何建设一个实用性强的网站 网站上线后如何运营