模拟string(一)详解


感谢各位大佬对我的支持,如果我的文章对你有用,欢迎点击以下链接
🐒🐒🐒 个人主页
🥸🥸🥸 C语言
🐿️🐿️🐿️ C语言例题
🐣🐣🐣 python
🐓🐓🐓 数据结构C语言
🐔🐔🐔 C++
🐿️🐿️🐿️ 文章链接目录

string()构造函数无参初始化

错误写法

class string
{
public:
	string()
		:_str(nullptr)
		, _size(0)
		,_capacity(0)
	{ }
private:
	char* _str;
	size_t _size;
	size_t _capacity;
};

这里的错误是_str(nullptr),因为C++要对C语言进行兼容
而有一个函数是下面这样的,返回指针

		const char* c_str()
	{
		return _str;
	}

如果返回的是空指针,然后我们将他打印,就会出现问题
在这里插入图片描述
而我们用库里面的就不会出现问题
在这里插入图片描述

代码

	class string
	{
	public:
		string()
			:_str(new char[1])
			, _size(0)
			, _capacity(0)
		{ 
			_str[0] = '\0';
		}
	private:
		char* _str;
		size_t _size;
		size_t _capacity;
	};
}

在这里插入图片描述

string(const char* str)构造函数有参初始化

错误写法

指针初始化的时候不可以像下面这样

class string
{
public:
	string(const char* str)
		:_str (str)
	{

	}
private:
	char* _str;
	size_t _size;
	size_t _capacity;
};

因为在初始化的时候传入的指针可能会是下面这样的情况

string s1 ("A")

将常量字符串传入,导致在初始化后我们不能将str修改,并且不可以扩容
所以正确写法是自己开空间拷贝数据

class string
{
	string(const char* str)
		:_size(strlen(str))
		, _str(new char[_size+1])
		,_capacity(strlen(str))
	{
		strcpy(_str, str);

	}
	private:
	char* _str;
	size_t _size;
	size_t _capacity;
};

这个顺序是不可以的,因为初始化列表的初始化顺序不是按实例化的顺序,而是按照声明的顺序初始化,这样就会导致_str在初始化的时候size为随机值,所以建议实例化顺序和声明顺序一致

代码

	class string
	{
	public:
		string(const char* str)
			:_str (new char[strlen(str)+1])
			,_size(strlen(str))
			,_capacity(strlen(str))
		{
			strcpy(_str, str);

		}
	private:
		char* _str;
		size_t _size;
		size_t _capacity;
	};

这个代码可以优化,对于strlen我们可以少调用

class string
{
public:
	string(const char* str)
		:_size(strlen(str))
	{
		_capacity = _size;
		_str = new char[_capacity + 1];
		strcpy(_str, str);

	}
private:
	char* _str;
	size_t _size;
	size_t _capacity;
};

string(const char* str = “”)合并无参和有参的构造函数代码

错误写法

下面这个代码是想利用缺省参数实现无参和有参的合并

	class string
	{
	public:
		string(const char* str=nullptr)
			:_size(strlen(str))
		{
			_capacity = _size;
			_str = new char[_capacity + 1];
			strcpy(_str, str);

		}
	private:
		char* _str;
		size_t _size;
		size_t _capacity;
	};

但是这样当我们传空指针的时候就会出现问题
在这里插入图片描述
而不传空指针就不会出现问题
在这里插入图片描述

这是因为strlen会对空指针进行解引用,strlen遇到\0才会停止,而空指针没有\0,所以就会崩溃
如果将缺省值改成string(const char* str=‘\0’)也会报错,因为\0是一个字符,将字符传给char *是不可以的
在这里插入图片描述

代码

所以缺省值应该是"\0"
在这里插入图片描述
当然我们也可以让缺省值写成"“,因为对于字符串来说,末尾都是以\0结尾,所以”\0"事实上有两个\0

	string(const char* str = "")
		:_size(strlen(str))
	{
		_capacity = _size;
		_str = new char[_capacity + 1];
		strcpy(_str, str);

	}

在这里插入图片描述

拷贝构造函数

浅拷贝

在没有实现拷贝构造函数的时候我们用的是编译器自动生成的拷贝构造函数,这时候会出现浅拷贝问题
在这里插入图片描述
通过调试我们可以看到s1和s2的地址是一样的
在这里插入图片描述
所以当结束后会先对s1析构,然后再对s2析构,但是因为s1和s2都指向同一块空间,导致这块空间析构两次,并且对s1进行修改数据的同时s2也会被修改

深拷贝

方法一string(const string& s)

根据上面的结果我们需要自己写一个深拷贝

	string(const string& s)
	{
		_str = new char[s._capacity + 1];
		strcpy(_str, s._str);
		_size = s._size;
		_capacity = s._capacity;
	}

其实就是s2开一块空间然后拷贝数据进去,然后s2指向这块开辟的空间
在这里插入图片描述

方法二string& operator=(const string& s)

代码
	string& operator=(const string& s)
	{
		char* tmp = new char[s._capacity + 1];
		strcpy(tmp, s._str);
		delete[]_str;
		_str = tmp;
		_size = s._size;
		_capacity = s._capacity;
		return *this;
	}

在这里插入图片描述
这样看起来没有什么问题

~string()析构函数

代码

	~string()
	{
		delete[] _str;
		_str = nullptr;
		_size = _capacity = 0;
	}
  • 32
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 14
    评论
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值