深拷贝(C++基础)

在字符串、指针或者带有指针的对象拷贝的时候,如果只是简单做了赋值处理,不能拷贝一份指针指向的内存地址,只是拷贝了一份指向内存地址的指针,在对拷贝过的内存操作的时候就很可能带来一些错误,比如释放了拷贝过的内存,之前拷贝前的内存也会被释放,因为根本是同一个内存地址。 

下面是一个基本类型的案例:

struct Vector2 {
	float x, y;
	Vector2(float x, float y) :x(x), y(y) {}
};

int main() {
	Vector2* a = new Vector2(1.0f,2.0f);
	Vector2* b = a;
	b->x = 3.0f;
	std::cout << a->x << std::endl;
	std::cout << b->y << std::endl;
	std::cout << b->x << std::endl;
}

可以看出,通过赋值后的指针指向,正常修改其指向值,复制对象指针指向的值也会被修改,因为在赋值时,只复制了指针,并没有赋值指向对象,下面通过一个字符串的例子进一步说明:

手写一个string类,

class String {
private:
	char* m_Buffer;
	unsigned int m_Size;
public:
	String(const char* string) {
		m_Size = strlen(string);
		m_Buffer = new char[m_Size + 1];
//需要算上终止符,加上1的长度,也可以使用strcpy函数,拷贝时会包含空终止符
		/*for (int i = 0; i < m_Size;i++) {
			m_Buffer[i] = string[i];
		}*/
		memcpy(m_Buffer, string, m_Size + 1);
//目的、来源、大小,少写了一个\0终止符
		m_Buffer[m_Size] = 0;//手动加上终止符
	}
	~String() {
		delete[] m_Buffer;
	}
	friend std::ostream& operator<<(std::ostream& stream, const String& string);//友元
};
void PrintString(String string) {
	std::cout << string << std::endl;
}
int main() {
	String string = "lhx";
	String second = string;
//浅拷贝,因为复制的指针,而指针作用的是同一片内存空间
	//解决办法,深拷贝:拷贝构造函数
	second[1] = 'v';
	PrintString(string);
	PrintString(second);
	std::cin.get();
}

second[1] = 'v';报错,因为没有对string类进行[]重载,并不能完成中括号数组的操作,在类中加上如下代码完成对[]的重载:

	char& operator[](unsigned int index) {
		return m_Buffer[index];
	}

运行后发现,输出都是lvx,并且在程序结束的时候会出线错误,说明lhx只有一个,并且被修改为lvx,而出现错误是因为在使用析构函数进行释放内存的时候,同一片内存被连续释放了。

 所以需要重写深拷贝构造方法,在类中加入如下代码:

	String(const String& other) :m_Size(other.m_Size) {
		std::cout << "deep copy" << std::endl;
		m_Buffer = new char[m_Size + 1];
		memcpy(m_Buffer, other.m_Buffer, m_Size + 1);
	}//深拷贝使用代码

发现被连续copy操作被连续调用,但不再出现错误:

为解决连续调用问题,对以下代码重写:

void PrintString(const String& string) {
	std::cout << string << std::endl;
}

要习惯总是通过const引用去传递对象,但在某些情况下,复制可能更快。

如果不带const,可以将临时的右值传递到实际函数,这个以后再说~

以下为全部代码:

#include<iostream>
#include<string>
struct Vector2 {
	float x, y;
	Vector2(float x, float y) :x(x), y(y) {}
};
class String {
private:
	char* m_Buffer;
	unsigned int m_Size;
public:
	String(const char* string) {
		m_Size = strlen(string);
		m_Buffer = new char[m_Size + 1];//需要算上终止符,加上1的长度,也可以使用strcpy函数,拷贝时会包含空终止符
		/*for (int i = 0; i < m_Size;i++) {
			m_Buffer[i] = string[i];
		}*/
		memcpy(m_Buffer, string, m_Size + 1);//目的、来源、大小,少写了一个\0终止符
		m_Buffer[m_Size] = 0;//手动加上终止符
	}

	//String(const String& other) :m_Buffer(other.m_Buffer), m_Size(other.m_Size) {}
	//String(const String& other) {
	//	memcpy(this, &other, sizeof(String));
	//}
	//String(const String& other) = delete;
	String(const String& other) :m_Size(other.m_Size) {
		std::cout << "deep copy" << std::endl;
		m_Buffer = new char[m_Size + 1];
		memcpy(m_Buffer, other.m_Buffer, m_Size + 1);
	}//深拷贝使用代码
	~String() {
		delete[] m_Buffer;
	}

	char& operator[](unsigned int index) {
		return m_Buffer[index];
	}
	friend std::ostream& operator<<(std::ostream& stream, const String& string);//友元
};
std::ostream& operator<<(std::ostream& stream, const String& string) {
	//stream << string.m_Buffer();
	stream << string.m_Buffer;
	return stream;
}
void PrintString(const String& string) {
	std::cout << string << std::endl;//如果不带const,可以将临时的右值传递到实际函数
	//总是通过const引用去传递对象,在某些情况下,复制可能更快
}
//void PrintString(String string) {
//	std::cout << string << std::endl;
//}
int main() {
	String string = "lhx";
	String second = string;//浅拷贝,因为复制的指针,而指针作用的是同一片内存空间
	//解决办法,深拷贝:拷贝构造函数
	second[1] = 'v';
	PrintString(string);
	PrintString(second);
	std::cin.get();
}

  • 14
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

想进大厂~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值