【C++】STL——string的模拟实现、常用构造函数、迭代器、运算符重载、扩容函数、增删查改

这篇具有很好参考价值的文章主要介绍了【C++】STL——string的模拟实现、常用构造函数、迭代器、运算符重载、扩容函数、增删查改。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.模拟实现string

string使用文章
【C++】STL——string的模拟实现、常用构造函数、迭代器、运算符重载、扩容函数、增删查改,C++,c++

1.1构造函数

  这里我们实现常用的第四个string(const char* s)和析构函数

【C++】STL——string的模拟实现、常用构造函数、迭代器、运算符重载、扩容函数、增删查改,C++,c++
【C++】STL——string的模拟实现、常用构造函数、迭代器、运算符重载、扩容函数、增删查改,C++,c++

class string {
public:
	//初始化列表赋值
	//string(const char* str = "\0")
	//	:_size(strlen(str))
	//	,_capacity(_size)
	//	,_str(new char[_capacity+1])
	//{
	//	memcpy(_str, str, _size + 1);
	//}
	
	//函数体内赋值
    string(const char* str = "\0") 
    {
        _size = strlen(str); // 获取字符串长度
        _capacity = _size; // 设置容量为长度
        _str = new char[_capacity + 1]; // 分配内存空间
        memcpy(_str, str, _size + 1); // 复制字符串内容
       	//strcpy(_str, str);
       	//这里最好不要使用strcpy,因为strcpy是C语言中的函数
       	//在检测到/0直接结束,若字符串中有/0,会导致部分字符串无法复制
    }

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

private:
    int _size; // 字符串长度
    int _capacity; // 字符串容量
    char* _str; // 字符串内容
};


  拷贝构造函数实现:

【C++】STL——string的模拟实现、常用构造函数、迭代器、运算符重载、扩容函数、增删查改,C++,c++

  在堆上使用new关键字为当前对象的成员变量_str分配内存空间,大小为s._capacity + 1字节,即字符串的容量加上一个结束符\0的空间。

  我们使用深拷贝而不是浅拷贝,浅拷贝会导致两个对象的指针指向同一块内存空间,当其中一个对象被析构时,会释放内存空间,导致另一个对象指向的内存变成悬空指针。 因此,在复制构造函数中使用了深拷贝来确保每个对象都有独立的内存空间存储字符串内容,避免出现悬空指针和程序崩溃的问题。

string(const string& s)
{
	this->_size = s._size;
	this->_capacity = s._capacity;
	
	//浅拷贝,两个指针指向同一块空间,且调用两次析构函数,程序崩溃
	//this->_str = s._str;

	//深拷贝 实现
	this->_str = new char[s._capacity + 1];
	//strcpy(_str, s.c_str());
	memcpy(_str, s.c_str(), _size + 1);
}

1.2迭代器

【C++】STL——string的模拟实现、常用构造函数、迭代器、运算符重载、扩容函数、增删查改,C++,c++
【C++】STL——string的模拟实现、常用构造函数、迭代器、运算符重载、扩容函数、增删查改,C++,c++

  我们通过迭代器来访问字符串的每个字符。begin 函数返回指向字符串的起始位置的迭代器,end 函数返回指向字符串的结束位置的迭代器。这样,就可以使用标准的迭代器操作来遍历字符串,如使用循环来遍历每个字符。

  对于普通的string类型,编译器调用上面两个类型iterator的迭代器,表示可以对该字符串可读可写;而对于const类型的string,编译器就会调用下面两个类型const_iterator的迭代器,表示对该字符串只有可写权限。

//实现迭代器和const迭代器
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;
}

1.3运算符重载

operator[]

【C++】STL——string的模拟实现、常用构造函数、迭代器、运算符重载、扩容函数、增删查改,C++,c++
  和上面的迭代器实现类似,我们也需要实现两个operator[]。

  重载的普通版本的 operator[] 函数接受一个 size_t 类型的位置参数 pos。它首先使用 assert 断言来检查指定的位置是否位于有效的范围内,即小于字符串的长度 _size。然后,它返回 _str[pos],也就是字符串中指定位置 pos 处的字符的引用。因为该函数返回的是一个引用,所以可以通过该引用对字符进行修改。

  重载的const版本的 operator[] 函数与版本类似,但是函数本身被声明为const成员函数,以确保不会修改对象的成员变量。这意味着对const对象时operator[]只能进行读的权限,但不能通过返回的引用来修改字符。

  通过重载 [] 操作符,可以像操作数组一样方便地访问类中的字符。例如,对于字符串对象 str,可以使用 str[0] 来访问第一个字符,str[1] 来访问第二个字符,以此类推。

//重载[]操作符
char& operator[](size_t pos)
{
	assert(pos < _size);

	return _str[pos];
}
 
//重载const[]操作符
const char& operator[](size_t pos) const
{
	assert(pos < _size);

	return _str[pos];
}

赋值运算符

【C++】STL——string的模拟实现、常用构造函数、迭代器、运算符重载、扩容函数、增删查改,C++,c++

【C++】STL——string的模拟实现、常用构造函数、迭代器、运算符重载、扩容函数、增删查改,C++,c++

  传统写法中的赋值操作符重载函数首先进行自我赋值的判断,以确保在自我赋值的情况下不会出现问题。 然后,创建一个临时的字符数组 tmp,大小为 s._capacity + 1,并使用 memcpy 函数将 s._str 的内容复制到 tmp 中。接下来,删除当前对象的 _str 所指向的内存空间,并将其指针指向新分配的 tmp。最后,更新当前对象的 _size 和 _capacity。

  现代写法中的赋值操作符重载函数使用了拷贝构造函数来简化实现。 它首先创建一个临时的字符串对象 tmp,并使用参数 s 初始化 tmp。然后,调用 swap 函数来交换当前对象的成员变量和 tmp 对象的成员变量。这样做的好处是,通过交换指针,可以避免进行手动的内存分配和释放,并且保证异常安全性。最后,返回当前对象的引用。

//传统写法
/*string& operator=(const string& s)
{
	if (this != &s)
	{
		char* tmp = new char[s._capacity + 1];
		memcpy(tmp, s._str, s._size + 1);
		delete[] _str;
		_str = tmp;

		_size = s._size;
		_capacity = s._capacity;
	}

	return *this;
}*/

//现代写法
void swap(string& s)
{
	std::swap(_str, s._str);
	std::swap(_size, s._size);
	std::swap(_capacity, s._capacity);
}

string& operator=(const string& s)
{
	if (this != &s)
	{
		string tmp(s);

		//this->swap(tmp);
		swap(tmp);
	}

	return *this;
}

//更简单的写法
//string& operator=(string tmp)
//{
//	swap(tmp);
//
//	return *this;
//}

其他用于string比较的运算符重载:

bool operator<(const string& s) const
{
	int ret = memcmp(_str, s._str, _size < s._size ? _size : s._size);
	return ret == 0 ? _size < s._size : ret < 0;
}

bool operator==(const string& s) const
{
	return _size == s._size
	&& memcmp(_str, s._str, _size) == 0;
}

bool operator<=(const string& s) const
{
	return *this < s || *this == s;
}

bool operator>(const string& s) const
{
	return !(*this <= s);
}

bool operator>=(const string& s) const
{
	return !(*this < s);
}

bool operator!=(const string& s) const
{
	return !(*this == s);
}

1.4扩容函数

reserve和resize

【C++】STL——string的模拟实现、常用构造函数、迭代器、运算符重载、扩容函数、增删查改,C++,c++
【C++】STL——string的模拟实现、常用构造函数、迭代器、运算符重载、扩容函数、增删查改,C++,c++

  这两个函数的作用是在需要扩容或调整字符串大小的情况下,确保字符串对象具有足够的容量和正确的大小。其中,reserve 函数用于扩容容量,resize 函数用于调整大小,并在必要时进行内存分配和字符填充。

//扩容capacity
void reserve(size_t n)
{
	if (n >= _capacity)
	{
		char* tmp = new char[n + 1];
		//strcpy(tmp,_str);
		memcpy(tmp, _str, _size + 1);

		delete[] _str;
		_str = tmp;
		_capacity = n;
	}
}

//扩容size
void resize(size_t n, char ch = '\0')
{
	if (n < _size)
	{
		_size = n;
		_str[_size] = '\0';
	}
	else
	{
		reserve(n);

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

		_size = n;
		_str[_size] = '\0';
	}
}

1.5增删查改

push_back和append和+=运算符重载

【C++】STL——string的模拟实现、常用构造函数、迭代器、运算符重载、扩容函数、增删查改,C++,c++
【C++】STL——string的模拟实现、常用构造函数、迭代器、运算符重载、扩容函数、增删查改,C++,c++

【C++】STL——string的模拟实现、常用构造函数、迭代器、运算符重载、扩容函数、增删查改,C++,c++

  这些函数的作用是向字符串对象中添加字符或字符数组。其中,push_back 可以用于逐个添加字符到字符串末尾,append 可以将字符数组追加到字符串中,operator+= 运算符重载则提供了一种简便的方式对字符串和字符进行连接。

//实现尾插
void push_back(const char ch)
{
	//先扩容
	if (_size == _capacity)
	{
		reserve(_capacity == 0 ? 4 : _capacity * 2);
	}

	this->_str[_size] = ch;

	++_size;
	this->_str[_size] = '\0';
}

//实现append
void append(const char* str)
{
	size_t len = strlen(str);
	if (_size + len > _capacity)
	{
		//至少要扩容到_size+len
		reserve(_size + len);
	}

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

//复用实现+=的运算符重载
string& operator+=(const char ch)
{
	push_back(ch);
	return *this;
}


完整实现(包含insert、erase、find、substr、operator<<、operator>>)文章来源地址https://www.toymoban.com/news/detail-609978.html

#include<assert.h>

namespace str
{
	class string
	{
	public:
		//实现迭代器和const迭代器
		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()
		//	:_size(0)
		//	, _capacity(_size)
		//	, _str(new char[1])
		//{
		//	_str[0] = '\0';
		//}

		构造函数传字符串
		//string(const char* str)
		//	:_size(strlen(str))
		//	,_capacity(_size)
		//	,_str(new char[_capacity+1])
		//{
		//	memcpy(_str, str, _size + 1);
		//}

		//合并string()和string(const char* str)
		//并且在函数体内赋值
		string(const char* str = "\0")//->"\0"\0
		{
			_size = strlen(str);
			_capacity = _size;
			_str = new char[_capacity + 1];
			//为空时,实参未显示赋值,我们给str缺省参数"\0"
			//str传给_str"\0",系统设为空
			//"\0"为字符串以指针传递、'\0'为单个字符以单个字符传递
			//strcpy(_str, str);
			memcpy(_str, str, _size + 1);
		}

		string(const string& s)
		{
			this->_size = s._size;
			this->_capacity = s._capacity;
			
			//浅拷贝,两个指针指向同一块空间,且调用两次析构函数,程序崩溃
			//this->_str = s._str;

			//深拷贝 实现
			this->_str = new char[s._capacity + 1];
			//strcpy(_str, s.c_str());
			memcpy(_str, s.c_str(), _size + 1);
		}

		//传统写法
		/*string& operator=(const string& s)
		{
			if (this != &s)
			{
				char* tmp = new char[s._capacity + 1];
				memcpy(tmp, s._str, s._size + 1);
				delete[] _str;
				_str = tmp;

				_size = s._size;
				_capacity = s._capacity;
			}

			return *this;
		}*/

		//现代写法
		void swap(string& s)
		{
			std::swap(_str, s._str);
			std::swap(_size, s._size);
			std::swap(_capacity, s._capacity);
		}

		//string& operator=(const string& s)
		//{
		//	if (this != &s)
		//	{
		//		string tmp(s);
		//
		//		//this->swap(tmp);
		//		swap(tmp);
		//	}
		//
		//	return *this;
		//}

		string& operator=(string tmp)
		{
			swap(tmp);

			return *this;
		}

		//析构函数
		~string()
		{
			_size = 0;
			_capacity = 0;
			delete[] _str;
			_str = nullptr;
		}

		//const返回c类型的字符串
		const char* c_str() const
		{
			return _str;
		}

		//const返回str的大小
		size_t size() const
		{
			return _size;
		}

		//重载[]操作符
		char& operator[](size_t pos)
		{
			assert(pos < _size);

			return _str[pos];
		}
		 
		//重载const[]操作符
		const char& operator[](size_t pos) const
		{
			assert(pos < _size);

			return _str[pos];
		}

		//扩容函数capacity
		void reserve(size_t n)
		{
			if (n >= _capacity)
			{
				char* tmp = new char[n + 1];
				//strcpy(tmp,_str);
				memcpy(tmp, _str, _size + 1);

				delete[] _str;
				_str = tmp;
				_capacity = n;
			}
		}

		//扩容size
		void resize(size_t n, char ch = '\0')
		{
			if (n < _size)
			{
				_size = n;
				_str[_size] = '\0';
			}
			else
			{
				reserve(n);

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

				_size = n;
				_str[_size] = '\0';
			}
		}

		//实现尾插
		void push_back(const char ch)
		{
			//先扩容
			if (_size == _capacity)
			{
				reserve(_capacity == 0 ? 4 : _capacity * 2);
			}

			this->_str[_size] = ch;

			++_size;
			this->_str[_size] = '\0';
		}

		//实现append
		void append(const char* str)
		{
			size_t len = strlen(str);
			if (_size + len > _capacity)
			{
				//至少要扩容到_size+len
				reserve(_size + len);
			}

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

		//复用实现+=的运算符重载
		string& operator+=(const char ch)
		{
			push_back(ch);
			return *this;
		}

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

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

			if (_size + n > _capacity)
			{
				reserve(_size + n);
			}

			size_t end = _size;
			while (end >= pos && end != npos)
			{
				_str[end + n] = _str[end];
				--end;
			}

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

			_size += n;
		}

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

			size_t len = strlen(str);
			if (_size + len > _capacity)
			{
				// 至少扩容到_size + len
				reserve(_size + len);
			}

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

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

			_size += len;
		}

		void erase(size_t pos, size_t len = npos)
		{
			assert(pos <= _size);

			if (len == npos || pos + len >= _size)
			{
				//_str[pos] = '\0';
				_size = pos;

				_str[_size] = '\0';
			}
			else
			{
				size_t end = pos + len;
				while (end <= _size)
				{
					_str[pos++] = _str[end++];
				}
				_size -= len;
			}
		}

		size_t find(char ch, size_t pos = 0)
		{
			assert(pos < _size);

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

			return npos;
		}

		size_t find(const char* str, size_t pos = 0)
		{
			assert(pos < _size);

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

		string substr(size_t pos = 0, size_t len = npos)
		{
			assert(pos < _size);

			size_t n = len;
			if (len == npos || pos + len > _size)
			{
				n = _size - pos;
			}

			string tmp;
			tmp.reserve(n);
			for (size_t i = pos; i < pos + n; i++)
			{
				tmp += _str[i];
			}

			return tmp;
		}

		void clear()
		{
			_str[0] = '\0';
			_size = 0;
		}

		//bool operator<(const string& s)
		//{
		//	size_t i1 = 0;
		//	size_t i2 = 0;
		//	while (i1 < _size && i2 < s._size)
		//	{
		//		if (_str[i1] < s._str[i2])
		//		{
		//			return true;
		//		}
		//		else if (_str[i1] > s._str[i2])
		//		{
		//			return false;
		//		}
		//		else
		//		{
		//			++i1;
		//			++i2;
		//		}
		//	}

		//	/*if (i1 == _size && i2 != s._size)
		//	{
		//		return true;
		//	}
		//	else
		//	{
		//		return false;
		//	}*/

		//	//return i1 == _size && i2 != s._size;
		//	return _size < s._size;
		//}

		bool operator<(const string& s) const
		{
			int ret = memcmp(_str, s._str, _size < s._size ? _size : s._size);
			return ret == 0 ? _size < s._size : ret < 0;
		}

		bool operator==(const string& s) const
		{
			return _size == s._size
				&& memcmp(_str, s._str, _size) == 0;
		}

		bool operator<=(const string& s) const
		{
			return *this < s || *this == s;
		}

		bool operator>(const string& s) const
		{
			return !(*this <= s);
		}

		bool operator>=(const string& s) const
		{
			return !(*this < s);
		}

		bool operator!=(const string& s) const
		{
			return !(*this == s);
		}

	private:
		int _size;
		int _capacity;
		char* _str;

	public:
		const static size_t npos;
	};

	const size_t string::npos = -1;

	ostream& operator<<(ostream& out, str::string& s)
	{
		//for (size_t i = 0; i < s.size(); i++)
		//{
		//	out << s[i];
		//}

		for (auto ch : s)
		{
			out << ch;
		}

		return out;
	}

	istream& operator>>(istream& in, std::string& s)
	{
		s.clear();

		char ch = in.get();
		while (ch == ' ' || ch == '\n')
		{
			ch = in.get();
		}

		//in >> ch;
		char buff[128];
		int i = 0;

		while (ch != ' ' && ch != '\n')
		{
			buff[i++] = ch;
			if (i == 127)
			{
				buff[i] = '\0';
				s += buff;
				i = 0;
			}

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

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

		return in;
	}
};

到了这里,关于【C++】STL——string的模拟实现、常用构造函数、迭代器、运算符重载、扩容函数、增删查改的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C++ STL string类模拟实现

    目录 string类成员变量 一.构造函数 二.析构函数 三.拷贝构造 四.size(),capacity() 五.operator [ ] 六. operator =  七.字符串比较  八.reserve() 九.push_back(),append() 十.operator+=  十一.insert()  十二.迭代器  十二.erase() 十三.swap()  十四.find() 十五.流提取,流输出 十六

    2024年02月14日
    浏览(52)
  • C++ [STL之string模拟实现]

    本文已收录至《C++语言》专栏! 作者:ARMCSKGT 前面我们介绍了STL容器string的部分接口使用,有了string使我们对字符串的操作如鱼得水,其实string不止于使用方便,其实现也有许多我们值得学习的地方,本节将为您介绍string常用接口的代码实现! 本文接口的实现借助于C++官方

    2024年02月05日
    浏览(49)
  • 【C++】STL之string功能及模拟实现

    目录 前沿 一、标准库中的string类 二、string类的常用接口说明  1、string类对象的常见构造  2、string类对象的容量操作  3、string类对象的访问及遍历操作  4、string类对象的修改操作  5、string类非成员函数  6、vs下string结构的说明 三、string类的模拟实现  1、构造函数  2、析

    2024年02月15日
    浏览(45)
  • 【C++精华铺】10.STL string模拟实现

            STL(标准模板库)是一个C++标准库,其中包括一些通用的算法、容器和函数对象。STL的容器是C++ STL库的重要组成部分,它们提供了一种方便的方式来管理同类型的对象。其中,STLstring是一种常用的字符串类型。         STLstring是一个类,它封装了字符串的操作

    2024年02月09日
    浏览(50)
  • STL中的string类的模拟实现【C++】

    构造函数设置为缺省参数,若不传入参数,则默认构造为空字符串。字符串的初始大小和容量均设置为传入C字符串的长度(不包括’\\0’) 在模拟实现拷贝构造函数前,我们应该首先了解深浅拷贝: 浅拷贝:拷贝出来的目标对象的指针和源对象的指针指向的内存空间是同一

    2024年02月15日
    浏览(41)
  • C++ STL学习之【string的模拟实现】

    ✨个人主页: Yohifo 🎉所属专栏: C++修行之路 🎊每篇一句: 图片来源 The key is to keep company only with people who uplift you, whose presence calls forth your best. 关键是只与那些提升你的人在一起,他们的存在唤起了你最好的一面。 string 本质上就是一个专注于存储字符的顺序表,使用起来

    2023年04月09日
    浏览(71)
  • 【c++】:模拟实现STL模板中的string

        文章目录 前言 一.string的模拟实现 总结   上一篇文章我们详细介绍了STL中的string的一些常用的接口,这一篇文章我们将从底层实现string类,当然我们只是实现一些重要的,经常使用的接口,并且不是完全按照STL中的string去走的。   首先我们为了防止我们写的string类与库

    2024年01月20日
    浏览(55)
  • C++ stl容器string的底层模拟实现

    目录 前言: 1.成员变量 2.构造函数与拷贝构造函数 3.析构函数 4.赋值重载 5.[]重载 6.比较关系重载 7.reserve 8.resize 9.push_back,append和重载+= 10.insert 11.erase 12.find 14.迭代器 15.流插入,流提取重载 16.swap 17.c_str 18.完整代码+测试 总结: 1.成员变量 首先注意的就是_str,不能是const类型

    2024年04月23日
    浏览(44)
  • 【C++初阶】STL详解(二)string类的模拟实现

    本专栏内容为:C++学习专栏,分为初阶和进阶两部分。 通过本专栏的深入学习,你可以了解并掌握C++。 💓博主csdn个人主页:小小unicorn ⏩专栏分类:C++ 🚚代码仓库:小小unicorn的代码仓库🚚 🌹🌹🌹关注我带你学习编程知识 注:为了防止与标准库当中的string类产生命名冲

    2024年02月05日
    浏览(57)
  • 【C++】反向迭代器的模拟实现通用(可运用于vector,string,list等模拟容器)

    🌏博客主页: 主页 🔖系列专栏: C++ ❤️感谢大家点赞👍收藏⭐评论✍️ 😍期待与大家一起进步! 我们要写出一个通用的反向迭代器模拟而且在保证代码简介不繁琐的的情况下,一定程度上使用我们自己模拟的已经封装好的iterator迭代器可以简化许多步骤,首先我们要知

    2024年02月14日
    浏览(55)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包