C++:浅拷贝的解决方法(深拷贝(传统写法,现代写法),写时拷贝)

本文介绍了C++中浅拷贝的概念,及其可能导致的问题,如野指针错误。接着详细讲解了两种深拷贝的实现方法:传统的深拷贝通过拷贝构造函数和赋值运算符重载实现,而现代方法则更简洁高效,但逻辑较复杂。最后,讨论了写时拷贝(COPY-ON-WRITE)的原理和优势,它结合了浅拷贝和深拷贝的优点,但在多线程环境下可能存在的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

什么是浅拷贝?

浅拷贝就是拷贝指向对象的指针,浅拷贝又称位拷贝,意思就是说:拷贝出来的目标对象的指针和源对象的指针指向的内存空间是同一块空间,浅拷贝只是一种简单的拷贝,让几个对象共用一个内存,然而当内存销毁的时候,指向这个内存空间的所有指针需要重新定义,不然会造成野指针错误

第一种方法:深拷贝

深拷贝就是: 给每个对象分配独立的内存资源,保证多个对象之间不会因为共享资源时,多次释放造成程序崩溃问题。
简单来说,就是增加了一个指针,并新开辟了一块空间,让指针指向这块新开辟的空间。

用深拷贝可以有两种方法实现:

1. 传统方法:
构造函数和析构函数较为简单和浅拷贝实现相同,在拷贝构造函数为对象开辟新的空间资源,在赋值运算符重载函数中需要注意在赋值时对原空间的释放,防止内存泄漏。
下面给出代码:

在实现时将类的实现放入命名空间bit1中,防止与标准库的string类发生冲突

namespace bit1
{
   
   
	class string
	{
   
   
	public:
		//构造函数
		string(const char* s = "") 
		{
   
   
			if (nullptr == s)//预防空指针的特殊情况
				s = "";
			_str = new char[strlen(s) + 1];
			strcpy(_str, s);
		}
		//拷贝构造函数
		string(const string& s) //这里使用引用是防止循环递归调用
			:_str(new char[strlen(s._str)+1])//为新对象开辟新的内存资源
		{
   
   
			strcpy(_str, s._str);
		}
		//赋值运算符重载函数
		string& operator=(const string& s)
		{
   
   
			if (&s != this)
			{
   
   
				char* ptr = new char[strlen(
### 深拷贝浅拷贝的基本区别 深拷贝浅拷贝C++中处理对象复制时的两种方式。**浅拷贝**指的是仅复制对象中的基本类型数据,而对于指针类型的成员变量,只复制其地址值,并不会重新分配内存并复制内容。这种操作可能导致多个对象共享同一块堆内存,从而在析构时引发重复释放的问题[^1]。 例如,默认的拷贝构造函数对指针进行的是浅拷贝: ```cpp class Person { public: std::string name; int* age; // 默认拷贝构造函数(浅拷贝) Person(const Person& p) { name = p.name; age = p.age; // 仅复制指针地址 } ~Person() { delete age; } }; ``` 上述代码中,`age`指针没有进行深拷贝,两个对象的`age`指向相同的内存空间,当两个对象析构时会尝试两次释放同一块内存,导致未定义行为[^3]。 --- ### 深拷贝的应用场景及实现方法 为了解决浅拷贝带来的问题,**深拷贝**会在拷贝构造函数中为指针成员重新申请一块新的内存,并将原对象的数据复制进去,使新旧对象之间不再共享堆内存。这种方式适用于类中包含动态分配的资源(如指针、文件句柄等)的情况[^5]。 例如,修改拷贝构造函数以实现深拷贝: ```cpp class Person { public: std::string name; int* age; // 自定义拷贝构造函数(深拷贝) Person(const Person& p) { name = p.name; age = new int(*p.age); // 新建内存并复制内容 } ~Person() { delete age; } }; ``` 这样,每个对象都有独立的堆内存,避免了重复释放的问题。同时,在函数参数传递或返回对象时,也会触发拷贝构造函数,因此需要特别注意是否使用了深拷贝来防止资源冲突[^1]。 --- ### 类外实现拷贝构造函数的方法 在实际开发中,为了保持类定义的简洁性和模块化,通常会将拷贝构造函数在类外部实现。此时需使用作用域解析运算符 `::` 来指定该函数属于哪个类。例如: ```cpp class Person { public: std::string name; int* age; Person(); // 构造函数 Person(const Person& p); // 声明拷贝构造函数 ~Person(); }; // 在类外实现拷贝构造函数 Person::Person(const Person& p) { name = p.name; age = new int(*p.age); // 深拷贝 } ``` 这样的写法不仅使得头文件更加清晰,也便于维护和调试。此外,对于模板类的拷贝构造函数,同样可以在类外实现,但需要注意添加模板参数列表: ```cpp template <typename T> class Array { public: T* data; int size; Array(int s); Array(const Array<T>& arr); // 模板类的拷贝构造函数声明 ~Array(); }; // 类外实现模板类的拷贝构造函数 template <typename T> Array<T>::Array(const Array<T>& arr) { size = arr.size; data = new T[size]; for (int i = 0; i < size; ++i) { data[i] = arr.data[i]; // 深拷贝 } } ``` 此类实现方式有助于提升代码可读性,并增强封装性[^2]。 --- ### 浅拷贝深拷贝在实际应用中的注意事项 当对象中存在指针成员时,除了在复制对象时需要考虑自定义拷贝构造函数,还应该关注以下两种情形: - **函数参数为对象时**:实参传递给形参的过程实际上是调用拷贝构造函数创建了一个临时对象。 - **函数返回值为对象时**:返回的对象通常是函数内部对象的一个拷贝,系统也会调用拷贝构造函数生成该副本。 如果未正确实现深拷贝,则在这些过程中可能会导致堆内存重复释放或数据不一致等问题[^4]。 此外,使用智能指针(如 `std::shared_ptr` 或 `std::unique_ptr`)可以自动管理内存生命周期,避免手动实现深拷贝浅拷贝带来的资源管理问题,是一种更现代且安全的替代方案。 --- ### 总结 深拷贝浅拷贝的核心区别在于是否为指针成员重新分配内存并复制内容。默认的拷贝构造函数执行的是浅拷贝,可能导致堆内存重复释放的问题;而通过自定义拷贝构造函数实现深拷贝可以有效解决这一问题。在类外实现拷贝构造函数有助于提高代码的可维护性和模块化程度,尤其适用于模板类等复杂结构。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值