string类的实现以及深浅拷贝

	//浅拷贝
	String(const String& str)
		:_data(str._data)
	{}
	//深拷贝,拷贝对象的内容和对象的资源
	String(const String& str)
		:_data(new char[strlen(str._data)+1])
	{
		strcpy(_data, str._data);
	}

浅拷贝:也称位拷贝,编译器只是将对象中的值拷贝过来。如果对象中管理资源,最后就会导致多个对象共享同一份资源,当一个对象销毁时就会将该资源释放掉,而此时另一些对象不知道该资源已经被释放,以为还有效,所以 当继续对资源进项操作时,就会发生发生了访问违规。要解决浅拷贝问题,C++中引入了深拷贝。
浅拷贝只是拷贝_data这个指针,深拷贝还会拷贝指针指向的内容“123”。
在这里插入图片描述

#include<stdio.h>
#include<iostream>
#include<string>
using namespace std;
class String
{
public:
	//构造函数
	String(const char* str=" ")
		:_data(new char[strlen(str)+1])
	{
		strcpy(_data, str);
	}
	//浅拷贝
	//String(const String& str)
		//:_data(str._data)
	//{}
	//深拷贝,拷贝对象的内容和对象的资源
	String(const String& str)
		:_data(new char[strlen(str._data)+1])
	{
		//拷贝资源
		strcpy(_data, str._data);
	}
	//赋值
	String& operator=(const String& str)
	{
		if (this != &str)
		{
			//释放原有的资源空间
			delete[] _data;
			//开辟新的资源空间
			_data = new char[strlen(str._data) + 1];
			//拷贝内容
			strcpy(_data, str._data);
		}
		return *this;
	}
	//析构函数
	~String()
	{
		if (_data)
		{
			delete[] _data;
			_data = nullptr;
		}
	}
private:
	char* _data;
};
void test()
{
	String str("hello");
	String str2("abc");
	String copy(str);
	//str2要调用string类的拷贝构造函数来构造,这样str2指向的资源和str指向的资源一样
	//在调用析构的时候,str2被销毁,str2和str指向的资源也被销毁
	//str成为野指针,在销毁str时出错,所以需要显式深拷贝构造函数
	str2 = str;//str2是第一个参数被this指针接收,str是第二个参数
	//先释放str2的资源,再让str2指向开辟的新的资源空间,再将str的内容拷贝过来
}

以上是传统写法
现代写法:

#include<stdio.h>
#include<iostream>
#include<string>
using namespace std;
class String {
public:
	String(const char* str = "")
		:_data(new char[strlen(str) + 1])//初始化对象,给对象开辟空间
	{
		strcpy(_data, str);//把参数中的内容拷贝到对象的_data中来
	}
	//拷贝构造,现代写法->复用拷贝的逻辑
	//借助构造函数在创建局部对象时,进行空间申请和内容拷贝
	//通过交换成员的指向达到深拷贝的目的
	String(const String& str)
		:_data(nullptr)//初始化为nullptr
	{
		String tmp(str._data);//创建一个新的tmp局部对象
		swap(_data, tmp._data);//交换tmp对象和当前对象,即可实现深拷贝
	}
	~String()
	{
		if (_data)
		{
			delete[] _data;
			_data = nullptr;
		}
	}
private:
	char* _data;
};
void test()
{
	String str = "1234";
	String copy(str);
}
int main()
{
	test();
	return 0;
}

在这里插入图片描述
在这里插入图片描述

	//现代赋值写法: 复用拷贝,借助拷贝构造完成:进行空间申请+内容拷贝
	//借用局部对象的析构函数完成当前对象原有资源的释放
	String& operator=(String str)//String str创建了一个局部对象
	{
		swap(_data, str._data);
		return *this;
	}
int main()
{
String str("123");
String str2("abc");
str2 = str;
}

在这里插入图片描述
string类的实现

#include<stdio.h>
#include<iostream>
#include<string>
#include<assert.h>
using namespace std;
class String {
public:
	//String的迭代器
	//实现:字符指针
	typedef char* iterator;
	typedef const char* const_iterator;
	iterator begin()
	{
		//第一个元素的位置
		return _data;
	}
	const_iterator begin()const
	{
		//第一个元素的位置
		return _data;
	}
	iterator end()
	{
		//最后一个元素的位置
		return _data + _size;
	}
	const_iterator end()const
	{
		//最后一个元素的位置
		return _data + _size;
	}
	String(const char* str = "")
		:_size(strlen(str))
		,_capacity(_size)
		, _data(new char[_size + 1])
	{
		strcpy(_data, str);
	}
	//拷贝构造
	String(const String& str)
		:_size(0)
		,_capacity(0)
		,_data(nullptr)//初始化为nullptr
	{
		String tmp(str._data);//创建一个新的tmp局部对象
		Swap(tmp);//交换tmp对象和当前对象,即可实现深拷贝
	}
	void Swap(String& str)//对象的所有成员都要拷贝
	{
		swap(_size, str._size);
		swap(_capacity, str._capacity);
		swap(_data, str._data);
	}
	//赋值
	String& operator=(String str)
	{
		Swap(str);
		return *this;
	}
	//析构
	~String()
	{
		if (_data)
		{
			delete[] _data;
			_data = nullptr;
			_size = _capacity = 0;
		}
	}
	//返回字符个数
	size_t size()const
	{
		return _size;
	}
	//返回容量
	size_t capacity()const
	{
		return _capacity;
	}
	char& operator[](size_t pos)//可读可写
	{
		assert(pos < _size);
		return _data[pos];
	}
	char& operator[](size_t pos)const//只读
	{
		assert(pos < _size);
		return _data[pos];
	}
	const char* c_str()const
	{
		return _data;
	}
	//尾插字符
	void pushBack(const char& ch)
	{
		//没有空余空间
		if (_size == _capacity)
		{
			//增容,2倍
			size_t newcap = _capacity == 0 ? 15 : 2 * _capacity;
			reserve(newcap);
		}
		//如果有空余空间
		_data[_size] = ch;
		++_size;
		_data[_size] = '\0';
	}
	//增加容量
	void reserve(size_t n)
	{
		//只增加容量
		if (n > _capacity)
		{
			//1.开辟一个空间
			char* tmp = new char[n+1];//加一是为'\0'留位置
			//2.拷贝
			strcpy(tmp, _data);
			//3.释放原有空间
			delete[]_data;
			//更新成员
			_data = tmp;
			_capacity = n;
		}
	}
	void resize(size_t n, const char& ch = '\0')//用‘\0’填充
	{
		// n > _capacity
		if (n > _capacity)
		{
			//增容
			reserve(n);
		}
		//_size < n <= _capacity,需要填充字符
		//for (size_t pos = _size; pos < n; pos++)
		//{
			//_data[pos] = ch;
		//}
		if(n>_size)
		memset(_data + _size, ch, sizeof(char)*(n - _size));//把剩下的空间全部填充为ch
		//当n小于等于_size时
		_size = n;
		_data[_size] = '\0';
	}
	//追加字符串
	void append(const char* str)
	{
		//1.检查容量
		int len = strlen(str);
		if (_size+len > _capacity)
		{
			//增容
			reserve(_size+len);
		}
		//2.插入
		memcpy(_data + _size, str, sizeof(char)*len);//效率更高,一次性拷贝,但不会拷贝\0
		//strcpy(_data + _size, str);
		//3.更新
		_size += len;
		_data[_size] = '\0';
	}
	//operator+=
	String& operator+=(const String& str)
	{
		append(str._data);
		return *this;
	}
	String& operator+=(const char* str)
	{
		append(str);
		return *this;
	}
	String& operator+=(const char str)
	{
		pushBack(str);
		return *this;
	}
	//在pos位置插入字符ch
	void insert(size_t pos, const char& ch)
	{
		//位置的检查,位置应该在0-size之间
		assert(pos <= _size);//因为pos是无符号类型,所以一定大于等于0
		//1.检查容量
		if (_size == _capacity)
		{
			size_t newC = _capacity == 0 ? 15 : 2 * _capacity;
			reserve(newC);
		}
		//2.移动元素,先移动后面的。
		size_t end = _size + 1;//最先移动的是'\0'
		while (end > pos)
		{
			_data[end] = _data[end - 1];
			end--;
		}
		//3.插入
		_data[pos] = ch;
		//更新
		_size++;
	}
	//在pos位置插入字符串ptr
	void insert(size_t pos, const char* ptr)
	{
		//检查位置
		assert(pos <= _size);
		int len = strlen(ptr);
		//检查容量
		if (_size+len > _capacity)
		{
			reserve(_size+len);
		}
		//移动元素
		size_t end = _size + len;
		while (end > pos + len - 1)
		{
			//pos + len    pos
			_data[end] = _data[end - len];
			--end;
		}
		//插入
		memcpy(_data + pos, ptr, sizeof(char)*len);
		//更新
		_size += len;
	}
	//删除
	void erase(size_t pos, size_t len = npos)
	{
		assert(pos < _size);
		//从pos位置开始,删除剩余的所有元素
		if (len == npos||pos +len >= _size)
			//如果不传入len参数,则len 和 npos相等,则把剩余元素全删除
			//或者要删除的元素大于等于元素的个数
		{
			_size = pos;
			_data[_size] = '\0';
		}
		else
		{//从前向后,每一个待移动的元素统一向前移动len个位置
			size_t start = pos + len;
			// [pos + len   _size]
			while (start <= _size)
			{
				_data[start - len] = _data[start];
				++start;
			}
			_size -= len;
		}
	}
	//查找字符
	size_t find(const char& ch, size_t pos = 0)
	{
		for (size_t i = pos; i < _size; i++)
		{
			if (_data[i] == ch)
			{
				return i;
			}
		}
		return npos;
	}
	//查找字符串
	size_t find(const char* ptr, size_t pos = 0)
	{
		assert(pos < _size);
		char* ptrpos = strstr(_data+pos, ptr);
		if (ptrpos)
		{
			return ptrpos - _data;
		}
		return npos;
	}
	//从pos位置截取len个字符
	String substr(size_t pos, size_t len = npos)
	{
		assert(pos <= _size);
		if (len == npos||pos + len >= _size)
		{
			String str(_data + pos);
			return str;
			//return String(_data+pos); 
		}
		else
		{
			char* newchar = new char[len+1];//动态开辟一个新空间
			//char new[len+1];在栈上开辟空间
			memcpy(newchar, _data + pos, sizeof(char)*len);//把要移动的字符串复制到这个新空间中
			newchar[len] = '\0';
			return String(newchar);//创建一个截取字符串的对象并返回
			delete[]newchar;
		}
	}
private:
	size_t _size;//有效字符的个数
	size_t _capacity;//容量:存放字符的最大个数
	char* _data;//先初始化size和capacity,再初始化数据空间
	static const size_t npos;
};
const size_t String::npos = -1;//静态变量要在类外初始化
String operator+(const String& str1, const String& str2)
{
	String str = str1;
	str += str2;
	return str;
}
String operator+(const char* str1, const String& str2)
{
	String str = str1;
	str += str2;
	return str;
}
String operator+(const char str1, const String& str2)
{
	String str = str2;
	str += str1;
	return str;
}
bool operator<(const String& str1, const String& str2)
{
	int ret = strcmp(str1.c_str(), str2.c_str());
	if (ret < 0)
		return true;
	else
		return false;
}
bool operator==(const String& str1, const String& str2)
{
	int ret = strcmp(str1.c_str(), str2.c_str());
	if (ret == 0)
		return true;
	else
		return false;
}
//输出
ostream& operator<<(ostream& out, const String& str)
{
	for (const auto& ch : str)
	{
		out << ch;
	}
	return out;
}
//输入
istream& operator>>(istream& in, String& str)
{
	char ch;
	while ((ch = cin.get())!=EOF)
	{
		if (ch == ' ' || ch == '\n')
			break;
		str += ch;
	}
	return cin;
}
void testout()
{
	String str("12345678");
	cout << str << str << endl;
}
void testpushback()
{
	String str;
	str.pushBack('1');
	str.pushBack('2');
	str.pushBack('3');
	for (auto&ch : str)
	{
		cout << ch << " ";
	}
	cout << endl;
}
void testfor()
{
	char arr[] = "abcdefg";
	for (const auto&ch : arr)
	{
		cout << ch << " ";
	}
	cout << endl;
	//范围for,底层调用迭代器访问
	String str = "123456789";
	for (auto&ch : str)
	{
		ch = 'a';
		cout << ch << " ";
	}
	cout << endl;
}
void test()
{
	String str = "123456789";
	for (size_t i = 0; i < str.size(); i++)
	{
		cout << str[i] << " ";//简写形式
		str[i] = i + 'a';//将每一个元素变为字母
		cout << str.operator[](i) << " ";//标准形式
		cout << endl;
	}
}
void print(const String& str)//不能修改内容,调用的是operator[]只读接口
{
	for (size_t i = 0; i < str.size(); i++)
	{
		cout << str[i] << " ";
	}
	cout << endl;
}
int main()
{
	testpushback();
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值