1. 爲什麼會有string類
處理char型數組,封裝標準C中一些字符串處理函數。
容器
2. 規格:有106個成員接口函數。
有如此之多的原因:
提高效率。(設計比較冗餘,爲了追求效率,省去了調用構造/析構函數及分配/釋放內存的時間)
用於實現常用操作
3.實現:C++標準沒有過多幹預,不同廠商有不同實現。
4.缺陷
不支持多進/線程;
模板技術水平沒跟上;
接口函數設計比較冗餘,同一個功能上實現了多次,而有一些功能卻沒有實現,且陷阱多;
不支持虛函數,阻止了多態性;
加劇了內存碎片問題。希望String類擁有自己的棧上內存來存放一些短字符串,而不需要總是去堆上分配內存。
採用的Copy-On-Write(COW)技術,因爲內存的共享,導致了程序在“多線程”環境中及容易發生錯誤,如果分別在兩個線程中的string實例共享着同一塊內存,很有可能發生潛在的內存問題。
標準的string類不支持policy-base技術的錯誤處理。string遇到錯誤時,只是簡單地拋出異常。不可能要且要求所有的程序都要在使用string操作的時候try catch。解決建議:string類封裝自己的error-handling函數,並且可以讓用戶來定義使用哪一種錯誤處理機制。
5.String類的簡單實現
#include<iostream> using namespace std; class String { public: String(); String(const char* str); ~String(); String(const String& s); String &operator=(const String & s); private: char* _str; }; String::String() :_str(new char[1]) { //cout << "無參構造函數" << endl; _str = '\0'; } String::String(const char* str = "") : _str(new char [strlen(str)+1]) { //cout << "帶參構造函數" << endl; strcpy(_str,str); } String::~String() { //cout << "析構函數" << endl; delete[] _str; } String::String(const String& s) :_str(new char[strlen(s._str)+1]) { //cout << "拷貝" << endl; strcpy(_str,s._str); } //String& String::operator=(const String & s) //{ // cout << "一般賦值運算符重載" << endl; // //檢查自賦值 // if (this == &s) // return *this; // //釋放原有的內存資源 // delete[] _str; // //分配新的內存資源,並複製內容 // _str = new char[strlen(s._str) + 1]; // strcpy(_str, s._str); // //返回本對象的引用 // return *this; //} //賦值的現代寫法 String& String::operator=(const String & s) { //cout << "現代賦值運算符重載" << endl; if (this == &s) return *this; //創建臨時變量,用於交換 String strtmp(s); char* ptmp = strtmp._str; strtmp._str = _str; _str = ptmp; //返回本對象的引用 return *this; } int main() { String s1("hello"); String s2(s1); String s3 = s1; s1 = s2; system("pause"); return 0; }
輸出結果:
(1)一般賦值運算符重載函數
(2)現代賦值運算符重載函數
實現表明:
在現代賦值運算符重載函數中,創建了一個臨時String對象(運用了拷貝構造函數),因爲此臨時String對象的作用域爲整個現代賦值運算符重載函數,出了這個函數就調用析構函數釋放內存資源,所以,現代賦值運算符重載函數比一般賦值運算符重載函數多兩個輸出。
第三行:String s3 = s1;我們明明是想用賦值運算符重載,實際調用的卻是拷貝構造函數。這是因爲編譯器優化的緣故,把本需調用構造函數構造s3再調用賦值運算符重載函數把s1拷貝給s3,編譯器直接優化爲利用拷貝構造函數構造s3。