String类深拷贝的现代写法和传统写法

本文对比了传统写法与现代写法下C++中自定义字符串类的实现方式,传统写法采用深拷贝,而现代写法通过构造临时对象与交换技巧避免了额外的空间分配。

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

1.传统写法:老老实实开辟空间并复制内容

2.现代写法:借助中间变量,交换指针


#include<iostream>
using namespace std;

//String类传统写法
namespace tradition
{
	class String
	{
	public:
		//构造
		String(char* str = "")
			:_str(new char[strlen(str)+1])		
		{
			strcpy(_str, str);
		}

		//拷贝构造
		String(const String& s)
		{
			_str = new char[strlen(s._str)+1];
			strcpy(_str, s._str);
		}

		//析构
		~String()
		{
			if(_str)
				delete[] _str;
		}

		//赋值运算符重载
		String& operator=(const String& s)
		{
			if(this != &s)		//防止自己给自己赋值
			{
				delete[] _str;						//释放原空间
				_str = new char[strlen(s._str)+1];	//开新空间
				strcpy(_str, s._str);				//赋值
			}
			return *this;
		}

		char* GetStr()
		{
			return _str;
		}

	private:
		char* _str;

	};
}

//String类现代写法
namespace modern
{
	class String	
	{
	public:
		//构造,析构,打印,都和传统写法一样
		String(char* str = "")
			:_str(new char[strlen(str)+1])
		{
			strcpy(_str, str);
		}

		~String()
		{
			delete[] _str;
		}

		char* GetStr()
		{
			return _str;
		}

		//拷贝构造,赋值运算符重载另外写,借助中间变量,不用直接开辟空间
		String(const String& s)
			:_str(NULL)
		{
			String tmp(s._str);		//构造函数
			swap(_str, tmp._str);
		}

		String& operator=(const String& s)
		{
			if(this != &s)
			{	
				String tmp(s._str);
				swap(_str, tmp._str);
			}
			return *this;
		}

	private:
		char* _str;
	};
}


### 深拷贝与浅拷贝的基本区别 深拷贝浅拷贝是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、付费专栏及课程。

余额充值