<三>对象的浅拷贝和深拷贝问题
2023-02-18 16:33:44 时间
先看示例代码
#include <iostream>
#include<cstring>
using namespace std;
class Student{
public:
Student(int _age , const char * _name)
{
this->age=_age;
int len=strlen(_name)+1;
char *tep=new char[len];
this->pName=tep;
strcpy(this->pName,_name);
}
~Student(){
delete[]this->pName;
this->pName=nullptr;
}
void showStudent(){
cout<<this->pName<<" "<<this->age<<endl;
}
private:
int age;
char *pName;
};
int main(){
Student s1(20,"zhangsan");
s1.showStudent();
Student s2=s1;
s2.showStudent();
return 1;
}
上面示例代码中,对象的默认拷贝方式是内存数据拷贝,如果对象占用了外部资源,那么就会出现问题了,这里的外部资源
就是在堆上申请的空间存放名字用,
s1,s2两个对象中的名字指针都是指向了同一块堆内存区域,在结束main函数的是,s2先析构,s2会析构调堆上的内存空间,
s1再析构,由于s1对象的pName 指针和s2对象的pName指针指向的是同一块堆内存区域,但是该区域内存已经被释放了,所以遇到了问题
鉴于上面的问题,我们引出了 浅拷贝,深拷贝的问题和解决方法.
Student s2=s1; 会调用拷贝构造函数(该拷贝构造函数可以是系统自动生成的,或者你自己定义一个拷贝构造函数)
系统自动生成的拷贝构造函数做的是内存数据拷贝,所以就出现了上面的问题.因此我们需要定义属于自己的拷贝构造函数
改造代码如下
class Student2{
public:
Student2(int _age , const char * _name)
{
this->age=_age;
int len=strlen(_name)+1;
char *tep=new char[len];
this->pName=tep;
strcpy(this->pName,_name);
cout<<"执行构造函数"<<endl;
}
//自定义拷贝构造函数
Student2(const Student2 &_stu2){
this->age=_stu2.age;
int len =strlen(_stu2.getPName())+1;
char *newPName =new char[len];
this->pName=newPName;
strcpy(this->pName,_stu2.getPName());
cout<<"执行拷贝构造函数"<<endl;
}
~Student2(){
if(this->pName!=nullptr){
delete[]this->pName;
this->pName=nullptr;
}
}
void showStudent(){
int *p=(int *)this->pName;
cout<<this->pName<<" "<<this->age<<" pName Heap Address ="<<p<<endl;
}
const char * getPName() const{
return this->pName;
}
private:
int age;
char *pName;
};
int main(){
Student2 s1(20,"zhangsan");
s1.showStudent();
Student2 s2=s1;
s2.showStudent();
return 1;
}
上面的代码还存在一个问题如下,如果在main函数中是下面的代码
Student2 s1(20,"zhangsan");
Student2 s2(30,"lisi");
s2=s1;
在main函数结束的是同样会遇到问题,这个时候就引出 赋值函数,我们需要定义自己的赋值函数
在 s2=s1这一段代码其实是这样调用的
s2.operator=(s1)
在你不定义自己的赋值函数的时候,系统会帮我们生成一个赋值函数,该赋值函数的赋值方式就是内存的数值拷贝,这种方式
在Student对象,会有问题,所以我们需要向自定义拷贝构造一样,定义一个属于自己的赋值函数
代码如下
class Student3{
public:
Student3(int _age , const char * _name)
{
this->age=_age;
int len=strlen(_name)+1;
char *tep=new char[len];
this->pName=tep;
strcpy(this->pName,_name);
cout<<"执行构造函数"<<endl;
}
//自定义拷贝构造函数
Student3(const Student3 & _stu){
this->age=_stu.age;
int len =strlen(_stu.getPName())+1;
char *newPName =new char[len];
this->pName=newPName;
strcpy(this->pName,_stu.getPName());
cout<<"执行拷贝构造函数"<<endl;
}
//自定义赋值函数
Student3 & operator= (const Student3 & _stu){
//防止自赋值
if(this==&_stu){return *this;}
//注意: 需要先释放当前的堆内存空间!!
delete []this->pName;
this->age=_stu.age;
int len =strlen(_stu.getPName())+1;
char *newPName =new char[len];
this->pName=newPName;
strcpy(this->pName,_stu.getPName());
cout<<"执行赋值函数"<<endl;
return *this;
}
~Student3(){
if(this->pName!=nullptr){
delete[]this->pName;
this->pName=nullptr;
}
}
void showStudent(){
int *p=(int *)this->pName;
cout<<this->pName<<" "<<this->age<<" pName Heap Address ="<<p<<endl;
}
const char * getPName() const{
return this->pName;
}
private:
int age;
char *pName;
};
int main(){
Student3 s3(20,"zhangsan");
s3.showStudent();
Student3 s4(30,"lisi");
s4=s3;
s4.showStudent();
return 1;
}
运用深拷贝浅拷贝实现String 代码如下
#include <iostream>
#include <cstring>
using namespace std;
class MyString{
public:
//构造函数
MyString(const char * src){
//创建空串
if(src==nullptr){
this->pchar=new char[1];
this->pchar[0]='\0';
}
else{
int len =strlen(src)+1;
this->pchar=new char[len];
strcpy(this->pchar,src);
}
cout<<"执行构造函数, 堆内存空间地址"<<(int *)this->pchar <<endl;
}
//拷贝构造
MyString(const MyString & myString){
//重新分配内存空间
int len =myString.stringLen()+1;
this->pchar=new char[len];
strcpy(this->pchar,myString.pchar);
cout<<"执行拷贝构造函数, 新创建堆内存空间地址"<<(int *)this->pchar <<endl;
}
//赋值函数
MyString & operator=(const MyString & myString){
//防止自赋值
if(this==&myString){return *this;}
//释放现有的堆内存空间
delete[]this->pchar;
this->pchar=nullptr;
int len =myString.stringLen()+1;
this->pchar=new char[len];
strcpy(this->pchar,myString.pchar);
cout<<"执行赋值函数, 新创建堆内存空间地址"<<(int *)this->pchar <<endl;
return *this;
}
int stringLen() const {
return strlen(this->pchar);
}
//析构
~MyString(){
delete [] this->pchar;
this->pchar=nullptr;
}
void printChar() const{
cout<<this->pchar<<endl;
}
private:
char *pchar;
};
int main(){
MyString s1("abcd");
s1.printChar();
MyString s2=s1;//执行拷贝构造
s2.printChar();
MyString s3("1234");
s3=s1;//执行赋值函数
s3.printChar();
return 1;
}
相关文章
- 聊聊 C++ 和 C# 中的 lambda 玩法
- C# 类继承中的私有字段都去了哪里?
- 聊聊 C# 中的多态底层 (虚方法调用) 是怎么玩的
- windbg的时间旅行实现对 C# 程序的终极调试
- 过早的给方法中 引用对象 设为 null 可被 GC提前回收吗?
- C#语法糖系列 —— 第三篇:聊聊闭包的底层玩法
- C#语法糖系列 —— 第二篇:聊聊 ref,in 修饰符底层玩法
- C#语法糖系列 —— 第一篇:聊聊 params 参数底层玩法
- 一个高频问题:异步操作会创建线程吗?
- 记一次 .NET 某供应链WEB网站 CPU 爆高事故分析
- 记一次 .NET 某智能交通后台服务 CPU爆高分析
- 记一次 .NET 某药品仓储管理系统 卡死分析
- 记一次 .NET 某消防物联网 后台服务 内存泄漏分析
- 记一次 WinDbg 分析 .NET 某工厂MES系统 内存泄漏分析
- 记一次 .NET 某市附属医院 Web程序 偶发性CPU爆高分析
- 记一次 .NET 某妇产医院 WPF内存溢出分析
- 记一次 .NET 某化妆品 webapi 卡死分析
- 记一次 .NET 某智能服装智造系统 内存泄漏分析
- 记一次 .NET 某电商无货源后端服务 死锁分析
- 记一次 .NET 某公交卡扣费系统 程序卡死分析