《C++ string 完全指南:string的模拟实现》

string的模拟实现


文章目录


一、浅拷贝和深拷贝


1.浅拷贝


2.深拷贝

如果一个类中涉及到资源的管理,其拷贝构造函数、赋值运算符重载以及析构函数必须要显式给出

一般情况都是按照 深拷贝 提供


3.写时拷贝


二、定义string的成员变量


三、string的接口实现

1.string的默认成员函数

(1)构造函数实现

这种短小频繁调用的函数,可以直接定义到类里面,默认是 inline


(2)析构函数实现

这里要注意一下判断 str是否为空


(3)拷贝构造函数



(4)赋值运算符重载


2.string的迭代器实现

string中迭代器iterator就是一个指针。所以我们直接使用typedef实现
begin()和end() 本质上都是 指针


3.string的容量操作函数

size()、capacity()、clear()、empty()都很简单!一看就懂!


接下来是reserve(),只要新容量大于旧容量就发生扩容。



4.string的访问操作函数

这部分较为简单,其实就是 数组的下表访问[ ]front()与back()


5.string的修改操作函数

两个常用的修改函数: push_back()与append()


+=就是在push_back和append的应用!


insert有两种类型,第一种类似于头插,第二种类似于任意位置插入
二者都需要挪动数据和检验数组的扩容问题


pop_back函数较为简单!
字符串的删除函数erase函数类似于尾删,也可以任意位置删除
将pos位置后所有字符往前移动len个单位,如果为字符len=1,否则len=字符串长度


6.string的查找函数

find函数既可以查找字符,也可以查找字符串(用strstr函数)


7.string的c_str和substr



8.string的< <= > >= == !=


9.string的operator>>

注意普通istream对象无法提前空格与\n。这是我们就需要一个函数get()来提取


四、源代码总结

1.String.h

代码如下(示例):

c 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include<iostream>
#include<string>
#include<assert.h>
using namespace std;
namespace bit
{
	class string
	{
	public:
		typedef char* iterator;
		typedef const char* const_iterator;
		iterator begin()
		{
			return _str;
		}
		iterator end()
		{
			return _str + _size;
		}
		const_iterator begin() const
		{
			return _str;
		}
		const_iterator end() const
		{
			return _str + _size;
		}
		/*string()
			:_str(new char[1]{'\0'})
			,_size(0)
			,_capacity(0)
		{}*/

		// 短小频繁调用的函数,可以直接定义到类里面,默认是inline
		string(const char* str = "")
		{
			_size = strlen(str);
			// _capacity不包含\0
			_capacity = _size;
			_str = new char[_capacity + 1];
			strcpy(_str, str);
		}

		// 深拷贝问题
		// s2(s1)
		/*string(const string& s)
		{
			_str = new char[s._capacity + 1];
			strcpy(_str, s._str);
			_size = s._size;
			_capacity = s._capacity;
		}*/

		void swap(string& s)
		{
			std::swap(_str, s._str);
			std::swap(_size, s._size);
			std::swap(_capacity, s._capacity);
		}

		// s2(s1)
		// 现代写法
		string(const string& s)
		{
			string tmp(s._str);
			swap(tmp);
		}

		// s2 = s1
		// s1 = s1
		/*string& operator=(const string& s)
		{
			if (this != &s)
			{
				delete[] _str;

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

			return *this;
		}*/

		// s1 = s3;
		//string& operator=(const string& s)
		//{
		//	if (this != &s)
		//	{
		//		//string tmp(s._str);
		//		string tmp(s);

		//		swap(tmp);
		//	}
		//	return *this;
		//}

		// s1 = s3;
		string& operator=(string tmp)
		{
			swap(tmp);

			return *this;
		}

		~string()
		{
			if (_str)
			{
				delete[] _str;
				_str = nullptr;
				_size = _capacity = 0;
			}
		}

		const char* c_str() const
		{
			return _str;
		}

		void clear()
		{
			_str[0] = '\0';
			_size = 0;
		}
		bool empty() const
		{
			return _size == 0;
		}

		size_t size() const
		{
			return _size;
		}

		size_t capacity() const
		{
			return _capacity;
		}
		// 可读可写
		char& front()
		{
			return _str[0];
		}
		char& back()
		{
			return _str[_size - 1];
		}
		// 可读不可写
		const char& front()const
		{
			return _str[0];
		}
		const char& back()const
		{
			return _str[_size - 1];
		}
		char& operator[](size_t pos)
		{
			assert(pos < _size);

			return _str[pos];
		}

		const char& operator[](size_t pos) const
		{
			assert(pos < _size);

			return _str[pos];
		}

		/*void copy_on_write()
		{
			if (count > 1)
			{
				深拷贝
			}
		}*/
		void reserve(size_t n);
		void push_back(char ch);
		void append(const char* str);
		string& operator+=(char ch);
		string& operator+=(const char* str);

		void insert(size_t pos, char ch);
		void insert(size_t pos, const char* str);
		void erase(size_t pos, size_t len = npos);

		size_t find(char ch, size_t pos = 0);
		size_t find(const char* str, size_t pos = 0);
		string substr(size_t pos = 0, size_t len = npos);
	private:
		//char _buff[16];
		char* _str = nullptr;
		size_t _size = 0;
		size_t _capacity = 0;

		//static const size_t npos = -1;
		static const size_t npos;

		/*static const int N = 10;
		int buff[N];*/
	};

	bool operator<(const string& s1, const string& s2);
	bool operator<=(const string& s1, const string& s2);
	bool operator>(const string& s1, const string& s2);
	bool operator>=(const string& s1, const string& s2);
	bool operator==(const string& s1, const string& s2);
	bool operator!=(const string& s1, const string& s2);

	ostream& operator<<(ostream& out, const string& s);
	istream& operator>>(istream& in, string& s);
}

2.String.cpp

代码如下(示例):

c 复制代码
#include"string.h"

namespace bit
{
	const size_t string::npos = -1;

	void string::reserve(size_t n)
	{
		if (n > _capacity)
		{
			//cout << "reserve:" << n << endl;

			char* tmp = new char[n + 1];
			strcpy(tmp, _str);
			delete[] _str;
			_str = tmp;
			_capacity = n;
		}
	}

	void string::push_back(char ch)
	{
		if (_size == _capacity)
		{
			reserve(_capacity == 0 ? 4 : _capacity * 2);
		}

		_str[_size] = ch;
		++_size;
		_str[_size] = '\0';
	}

	string& string::operator+=(char ch)
	{
		push_back(ch);
		return *this;
	}

	void string::append(const char* str)
	{
		size_t len = strlen(str);
		if (_size + len > _capacity)
		{
			// 大于2倍,需要多少开多少,小于2倍按2倍扩
			reserve(_size + len > 2 * _capacity ? _size + len : 2 * _capacity);
		}

		strcpy(_str + _size, str);
		_size += len;
	}

	string& string::operator+=(const char* str)
	{
		append(str);
		return *this;
	}

	void string::insert(size_t pos, char ch)
	{
		assert(pos <= _size);

		if (_size == _capacity)
		{
			reserve(_capacity == 0 ? 4 : _capacity * 2);
		}

		// 挪动数据
		size_t end = _size + 1;
		while (end > pos)
		{
			_str[end] = _str[end - 1];
			--end;
		}

		_str[pos] = ch;
		++_size;
	}

	void string::insert(size_t pos, const char* s)
	{
		assert(pos <= _size);

		size_t len = strlen(s);
		if (_size + len > _capacity)
		{
			// 大于2倍,需要多少开多少,小于2倍按2倍扩
			reserve(_size + len > 2 * _capacity ? _size + len : 2 * _capacity);
		}

		size_t end = _size + len;
		while (end > pos + len - 1)
		{
			_str[end] = _str[end - len];
			--end;
		}

		for (size_t i = 0; i < len; i++)
		{
			_str[pos + i] = s[i];
		}

		_size += len;
	}
	void string::erase(size_t pos, size_t len)
	{
		assert(pos < _size);

		if (len >= _size - pos)
		{
			_str[pos] = '\0';
			_size = pos;
		}
		else
		{
			for (size_t i = pos + len; i <= _size; i++)
			{
				_str[i - len] = _str[i];
			}

			_size -= len;
		}
	}

	size_t string::find(char ch, size_t pos)
	{
		assert(pos < _size);

		for (size_t i = pos; i < _size; i++)
		{
			if (_str[i] == ch)
			{
				return i;
			}
		}

		return npos;
	}

	size_t string::find(const char* str, size_t pos)
	{
		assert(pos < _size);

		const char* ptr = strstr(_str + pos, str);
		if (ptr == nullptr)
		{
			return npos;
		}
		else
		{
			return ptr - _str;
		}
	}

	string string::substr(size_t pos, size_t len)
	{
		assert(pos < _size);

		// len大于剩余字符长度,更新一下len
		if (len > _size - pos)
		{
			len = _size - pos;
		}

		string sub;
		sub.reserve(len);
		for (size_t i = 0; i < len; i++)
		{
			sub += _str[pos + i];
		}

		return sub;
	}

	bool operator<(const string& s1, const string& s2)
	{
		return strcmp(s1.c_str(), s2.c_str()) < 0;
	}
	bool operator<=(const string& s1, const string& s2)
	{
		return s1 < s2 || s1 == s2;
	}
	bool operator>(const string& s1, const string& s2)
	{
		return !(s1 <= s2);
	}
	bool operator>=(const string& s1, const string& s2)
	{
		return !(s1 < s2);
	}
	bool operator==(const string& s1, const string& s2)
	{
		return strcmp(s1.c_str(), s2.c_str()) == 0;
	}
	bool operator!=(const string& s1, const string& s2)
	{
		return !(s1 == s2);
	}

	ostream& operator<<(ostream& out, const string& s)
	{
		for (auto ch : s)
		{
			out << ch;
		}

		return out;
	}

	// 17:16继续
	istream& operator>>(istream& in, string& s)
	{
		s.clear();

		const int N = 256;
		char buff[N];
		int i = 0;

		char ch;
		//in >> ch;
		ch = in.get();
		while (ch != ' ' && ch != '\n')
		{
			buff[i++] = ch;
			if (i == N - 1)
			{
				buff[i] = '\0';
				s += buff;

				i = 0;
			}

			//in >> ch;
			ch = in.get();
		}

		if (i > 0)
		{
			buff[i] = '\0';
			s += buff;
		}

		return in;
	}
}

相关推荐
遇见尚硅谷4 小时前
C语言:20250728学习(指针)
c语言·开发语言·数据结构·c++·笔记·学习·算法
☆璇4 小时前
【C++】C/C++内存管理
c语言·开发语言·c++
铭哥的编程日记5 小时前
《C++ list 完全指南:从基础到高效使用》
开发语言·c++·list
岁忧5 小时前
(LeetCode 面试经典 150 题 ) 155. 最小栈 (栈)
java·c++·算法·leetcode·面试·go
铭哥的编程日记8 小时前
《C++继承详解:从入门到理解公有、私有与保护继承》
c++
qq_433554548 小时前
C++ 哈希算法、贪心算法
开发语言·c++·哈希算法
CYRUS_STUDIO8 小时前
动态篡改 so 函数返回值:一篇带你玩转 Android Hook 技术!
android·c++·逆向
liulilittle9 小时前
DDD领域驱动中瘦模型与富态模型的核心区别
开发语言·c++·算法·ddd·领域驱动·思想
Yu_Lijing9 小时前
MySQL进阶学习与初阶复习第二天
数据库·c++·学习·mysql