一、傳統的實現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; };