C++_string类模拟实现

1、string类浅拷贝造成的问题

/*
 *此程序会崩溃
 *由于s2对s1浅拷贝,导致多次释放同一块空间
 * */

#include<iostream>
#include<cstring>
#include<cstdlib>
#include<assert.h>

using namespace std;

class String
{
public:
	String(const char * str = "")
	{
		if(nullptr == str)
		{
			assert(false);
			return;
		}
		_str = new char[strlen(str) + 1];
		strcpy(_str, str);
	}
	~String()
	{
		if(_str)
		{
			delete[] _str;
			_str = nullptr;
		}
	}
private:
	char * _str;
};

int main()
{
	String s1("hello");
	String s2(s1);
	return 0;
}
  • String类没有显式定义其拷贝构造函数与赋值运算符重载,此时编译器会合成默认的,当用s1构造s2时,编译器会调用默认的拷贝构造,导致s1、s2共用同一块内存空间。
  • 在释放时,s2将其_str所指空间释放掉,s2对象成功销毁,s1中_str成为野指针,销毁出错,同一块空间被释放多次而引起程序崩溃,这种拷贝方式称为浅拷贝。

2、浅拷贝

  • 浅拷贝,也称位拷贝,编译器只是将对象中的值拷贝过来
  • 如果对象中管理资源,就会导致多个对象共享同一份资源
  • 当一个对象销毁时就会将该资源释放掉,而此时另一些对象不知道该资源已经被释放,以为还有效,所以当继续对资源进项操作时,就会发生访问违规
  • 引入深拷贝解决浅拷贝问题

3、深拷贝

如果一个类中涉及到资源的管理,其拷贝构造函数、赋值运算符重载以及析构函数必须要显式给出。一般情况都是按照深拷贝方式提供。

String(const String& s)
	:_pStr(new char[strlen(s._pStr) + 1])
{
	strcpy(_pStr, s._pStr);
}

深拷贝:给每个对象独立分配资源,保证多对象之间不会因资源共享造成多次释放引起的程序崩溃

#include<iostream>
#include<cstring>
#include<cstdlib>
#include<assert.h>

using namespace std;

class String
{
public:
	String(const char * str = "")
	{
		if(nullptr == str)
		{
			assert(false);
			return;
		}
		_str = new char[strlen(str) + 1];
		strcpy(_str, str);
	}
	String(const String& str)
		:_str(new char[strlen(str._str) + 1])
	{
		strcpy(_str, str._str);
	}
	String& operator=(const String& str)
	{
		if(this != &str)
		{
			delete[] _str;
			_str = new char[strlen(str._str) + 1];
			strcpy(_str, str._str);
		}
		return *this;
	}
	~String()
	{
		if(_str)
		{
			delete[] _str;
			_str = nullptr;
		}
	}
	void display()
	{
		cout<<_str<<endl;
	}
private:
	char * _str;
};

int main()
{
	String s1("hello");
	String s2(s1);
	String s3 = s2;
	s1.display();
	s2.display();
	s3.display();
	return 0;
}

4、写时拷贝

  • 写时拷贝:是在浅拷贝的基础之上增加了引用计数的方式来实现的。
  • 引用计数:用来记录资源使用者的个数。在构造时,将资源的计数给成1,每增加一个对象使用该资源,就给计数增加1,当某个对象被销毁时,先给该计数减1,然后再检查是否需要释放资源,如果计数为1,说明该对象时资源的最后一个使用者,将该资源释放,否则就不能释放,因为还有其他对象在使用该资源。

5、string类的模拟实现

#include<iostream>
#include<cstdlib>
#include<cstring>
#include<assert.h>

using namespace std;

class String
{
public:
	typedef char * iterator;

public:
	String(const char * str = "")
	{
		if(str == nullptr)
		{
			str = "";
		}
		_size = strlen(str);
		_capacity = 10;
		_str = new char[_capacity + 1];
		strcpy(_str, str);
	}

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

	String& operator=(const String& s)
	{
		if(this != &s)
		{
			delete[] _str;
			_size = s._size;
			_capacity = s._capacity;
			_str = new char[_capacity + 1];
			strcpy(_str, s._str);
		}
		return *this;
	}

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

	iterator begin()
	{
		return _str;
	}

	iterator end()
	{
		return _str + _size;
	}

	void PushBack(char c)
	{
		if(_size == _capacity)
		{
			Reserve(_capacity * 2);
		}
		_str[_size] = c;
		_str[++_size] = '\0';
	}

	String& operator+=(char c)
	{
		PushBack(c);
		return *this;
	}

	void Append(const char * str)
	{
		for(int i = 0; i < strlen(str); ++i)
		{
			PushBack(str[i]);
		}
	}

	String& operator+=(const char * str)
	{
		Append(str);
		return *this;
	}

	void Clear()
	{
		strcpy(_str, "");
		_size = strlen(_str);
		_capacity = 10;
		_str = new char[_capacity + 1];
	}

	void Swap(String& s)
	{
		swap(_str, s._str);
		swap(_size, s._size);
		swap(_capacity, s._capacity);
	}

	const char * C_str() const
	{
		return _str;
	}
	
	size_t Size() const
	{
		return _size;
	}

	size_t Capacity() const
	{
		return _capacity;
	}

	bool Empty() const
	{
		if(_size == 0)
		{
			return 1;
		}
		return 0;
	}

	void Resize(size_t newSize, char c = '\0')
	{
		if(newSize > _size)
		{
			if(newSize > _capacity)
			{
				Reserve(newSize);
			}
			memset(_str + _size, c, newSize - _size);
		}
		_size = newSize;
		_str[newSize] = '\0';
	}

	void Reserve(size_t newCapacity)
	{
		if(newCapacity > _capacity)
		{
			char * tmp = new char[newCapacity + 1];
			strcpy(tmp, _str);
			delete[] _str;
			_str = tmp;
			_capacity = newCapacity;
		}
	}

	char& operator[](size_t index)
	{
		assert(index < _size);
		return _str[index];
	}

	const char& operator[](size_t index) const
	{
		assert(index < _size);
		return _str[index];
	}

	bool operator<(const String& s)
	{
		if((*this) == s)
		{
			return false;
		}
		for(int i = 0; i < _size; ++i)
		{
			if(_str[i] < s._str[i])
			{
				return true;
			}
			else if(_str[i] > s._str[i])
			{
				return false;
			}
		}
		if(_size < s._size)
		{
			return true;
		}
	}

	bool operator<=(const String& s)
	{
		if(((*this) < s) || ((*this) == s))
		{
			return true;
		}
		return false;
	}

	bool operator>(const String& s)
	{
		if((*this) == s)
		{
			return false;
		}
		for(int i = 0; i < _size; ++i)
		{
			if(_str[i] > s._str[i])
			{
				return true;
			}
			else if(_str[i] < s._str[i])
			{
				return false;
			}
		}
		if(_size < s._size)
		{
			return false;
		}
	}

	bool operator>=(const String& s)
	{
		if(((*this) > s) || ((*this) == s))
		{
			return true;
		}
		return false;
	}
	
	bool operator==(const String& s)
	{
		if(s._size != _size)
		{
			return false;
		}
		for(int i = 0; i < _size; ++i)
		{
			if(s[i] != _str[i])
			{
				return false;
			}
		}
		return true;
	}

	bool operator!=(const String& s)
	{
		if(s._size != _size)
		{
			return true;
		}
		for(int i = 0; i < _size; ++i)
		{
			if(s[i] != _str[i])
			{
				return true;
			}
		}
		return false;
		/*
		if((*this) == s)
		{
			return false;
		}
		return true;
		*/
	}

	size_t Find(char c, size_t pos = 0) const
	{
		for(int i = pos; i < _size; ++i)
		{
			if(c == _str[i])
			{
				return i;
			}
		}
		return -1;
	}

	size_t Find(const char * s, size_t pos = 0) const
	{
		for(int i = pos; i < _size; ++i)
		{
			int j = 0;
			for(j = 0; j < strlen(s); ++j)
			{
				if(s[j] != _str[i + j])
				{
					break;
				}
			}
			if(j == strlen(s))
			{
				return i;
			}
		}
		return -1;
	}

	String& Insert(size_t pos, char c)
	{
		if(_size == _capacity)
		{
			Reserve(_capacity * 2);
		}
		_str[_size + 1] = '\0';
		for(int i = _size - 1; i >= pos; --i)
		{
			_str[i + 1] = _str[i];
		}
		_str[pos] = c;
		_size++;
		return *this;
	}

	String& Insert(size_t pos, const char * str)
	{
		for(int i = 0; i < strlen(str); ++i)
		{
			Insert(pos + i, str[i]);
		}
		return *this;
	}

	String& Erase(size_t pos, size_t len)
	{
		int index = pos;
		for(int i = pos + len; i < _size; ++i)
		{
			_str[pos++] = _str[i];
		}
		_str[pos] = '\0';
		_size -= len;
		return *this;
	}

private:
	friend ostream& operator<<(ostream& _cout, const String& s);

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

ostream& operator<<(ostream& _cout, const String& s)
{
	_cout<<s._str<<" "<<s._size<<" "<<s._capacity;
	return _cout;
}

int main()
{
	String s1("hello");
	cout<<s1<<endl;
	cout<<s1.Size()<<endl;
	cout<<s1.Capacity()<<endl;
	cout<<s1.Empty()<<endl;
	s1.PushBack('c');
	cout<<s1<<endl;
	s1 += 'c';
	cout<<s1<<endl;
	s1.Append("linux");
	cout<<s1<<endl;
	s1 += "code";
	cout<<s1<<endl;
	s1.Clear();
	cout<<s1<<endl;
	s1.Append("linux");
	cout<<s1<<endl;
	String s2;
	cout<<s2<<endl;
	s2.Append("linuxcode");
	cout<<s2<<endl;
	s1.Swap(s2);
	cout<<s1<<endl;
	cout<<s1.C_str()<<endl;
	cout<<s2<<endl;
	s2.Resize(20);
	cout<<s2<<endl;
	cout<<s2[2]<<endl;
	String s3("hello");
	String s4("linux");
	cout<<"s3==s4:"<<(s3==s4)<<endl;
	cout<<"s3!=s4:"<<(s3!=s4)<<endl;
	cout<<"s3<s4:"<<(s3<s4)<<endl;
	cout<<"s3<=s4:"<<(s3<=s4)<<endl;
	cout<<s4<<endl;
	cout<<s4.Find("nux")<<endl;
	s4.Insert(2, " hello code ");
	cout<<s4<<endl;
	s4.Erase(2, 12);
	cout<<s4<<endl;
	return 0;
}

Makefile文件:

.PHONY:all
all:String

String:String.cpp
	g++-4.8 -std=c++11 -o $@ $^

.PHONY:clean
clean:
	rm -rf String
发布了72 篇原创文章 · 获赞 25 · 访问量 7333

猜你喜欢

转载自blog.csdn.net/qq_41245381/article/details/104006782