c++中string類的基本功能的實現(1)

一、傳統的實現string類的方法ios

優勢:程序簡單易懂ide

缺點:函數

1)在實現其拷貝構造和賦值的操做時屢次的調用new動態的開闢空間,所以也須要屢次的經過delete來釋放空間。若是處理不當還容易形成內存泄漏。this

2)程序的一致性比較差spa

#include <iostream>
#include <string>
using namespace std;

class String 
{
public:
	// 構造函數
	String(char *str = "")
		:_str(new char [strlen(str)+1])
	{
		if (_str != NULL)
		{
			strcpy(_str, str);
		}
	}
	//拷貝構造
	String(const String& str)
		:_str(new char[strlen(str._str) + 1])
	{
		if (_str != NULL)
		{
			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()
	{
		delete [] _str;
	}

private:
	char * _str;
};

二、現代的實現string類的方法寫實指針

拷貝構造實現思路:對象

a)建立一個臨時對象,並經過cconst String._str來構造。內存

b)構造完成以後將臨時對象的_str和this._str進行交換進而使得對象的內容交換來完成拷貝構造字符串

賦值實現思路:string

經過參數的值傳遞來構造對象,並將對象的內容交換

優勢:

1)程序的一致性比較好

2)只是在構造函數中出現了開闢空間的new,只在析構函數中出現了delete結構清晰,不容易形成內存泄漏

class String 
{
public:
	// 構造函數
	String(char *str = "")
		:_str(new char [strlen(str)+1])
	{
		if (_str != NULL)
		{
			strcpy(_str, str);
		}
	}
	
	//拷貝構造
	String(const String& str)
		:_str(NULL)//防止其指向一份不合法的空間
	{
		String tmp(str._str);
		swap(_str, tmp._str);
	}

	//賦值
	String& operator =(String str)
	{
		swap(_str, str._str);
		return *this;
	}

	//析構函數
	~String()
	{
		delete [] _str;
	}
private:
	char * _str;
};


三、寫實函數提升string類的效率

在以上的兩種string類的實現方法中,都存在一個效率的問題。有的時候字符串比較長,並且對象創建以後也不必定更改。可是以上兩種方法不管什麼時候都須要構建,其效率比較低並且會帶來內存的浪費。

咱們能夠經過讓全部指向相同字符串內容的對象指向同一份空間,經過計數器來記錄對象的個數,避免析構出現錯誤。

因此能夠經過在開闢對象的時候多開闢4個字節的空間,來存放計數器。若是修改的時候再開闢空間。

#define _CRT_SECURE_NO_WARNINGS

#include<iostream>
#include <string>
using namespace std;

class String 
{
public:
	//構造函數
	String(char *str="")
		:_Pstr(FindStartRef(new char[strlen(str)+1+sizeof(int)]))
	{
		*Count(_Pstr) = 1;//計數器
		strcpy(_Pstr, str);//將字符串拷貝
	}

	//拷貝構造函數
	//若是不更改對象的內容則讓多個對象的字符指針指向同一份空間
	String(const String& s)
	{
		_Pstr = s._Pstr;
		(*Count(_Pstr))++;//計數器加1
	}

	//賦值語句
	//若是不更改對象的內容則讓多個對象的字符指針指向同一份空間
	String& operator =(const String& s)
	{
		if (this != &s)//避免自賦值
		{
			if (--*(Count(_Pstr)) == 0)
			{
				delete[]FindDel(_Pstr);
			}//只有一個對象使用的一份空間則釋放
			else
			{
				_Pstr = s._Pstr;
				(*Count(_Pstr))++;
			}
		}
		return *this;
	}

	//析構函數
	~String()
	{
		if (--*(Count(_Pstr)) == 0)
		{
			delete[]FindDel(_Pstr);
		}
	}
public:
	//找到開闢空間時的存放字符串的首地址
	char * FindStartRef(char* str)
	{
		return (str + 4);
	}

	//找到釋放空間時的首地址
	char * FindDel(char* del)
	{
		return (del - 4);
	}

	//找到計數器的首地址
	int *Count(char* str)
	{
		return (int *)(str - 4);
	}
public:
	//修改寫實對象的內容函數
	char & operator[](int index)
	{
		if (--*(Count(_Pstr)) != 0)
		{
			char * tmp = _Pstr;
			_Pstr = FindStartRef(new char[strlen(_Pstr) + 1 + sizeof(int)]);
			*Count(_Pstr) = 1;//計數器置1
			strcpy(_Pstr, tmp);
		}//若是該對象和其餘對象公用一份空間
		else
		{
			//單獨使用一份空間能夠隨意更改
		}
		return _Pstr[index];
	}
private:
	char * _Pstr;
};
相關文章
相關標籤/搜索