亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C++ > 正文

探究C++中string類的實現原理以及擴展使用

2020-05-23 14:11:30
字體:
來源:轉載
供稿:網友
這篇文章主要介紹了C++中string類的實現原理以及擴展使用,從內存分配角度進行了深入探究,需要的朋友可以參考下
 

C++程序員編碼過程中經常會使用string(wstring)類,你是否思考過它的內部實現細節。比如這個類的迭代器是如何實現的?對象占多少字節的內存空間?內部有沒有虛函數?內存是如何分配的?構造和析構的成本有多大?筆者綜合這兩天閱讀的源代碼及個人理解簡要介紹之,錯誤的地方望讀者指出。

首先看看string和wstring類的定義:

typedef basic_string<char, char_traits<char>, allocator<char> > string; typedef basic_string<wchar_t, char_traits<wchar_t> allocator<wchar_t> > wstring; 

從這個定義可以看出string和wstring分別是模板類basic_string對char和wchar_t的特化。

再看看basic_string類的繼承關系(類方法未列出):

探究C++中string類的實現原理以及擴展使用

最頂層的類是_Container_base,它也是STL容器的基類,Debug下包含一個_Iterator_base*的成員,指向容器的最開始的元素,這樣就能遍歷容器了,并定義了了兩個函數

void _Orphan_all() const;  // orphan all iterators void _Swap_all(_Container_base_secure&) const; // swaps all iterators 

Release下_Container_base只是一個空的類。

_String_base類沒有數據成員,只定義了異常處理的三個函數:

static void _Xlen();  // report a length_error static void _Xran();  // report an out_of_range error static void _Xinvarg(); 

_String_val包含一個alloctor的對象,這個類也非常簡單,除了構造函數沒有定義其它函數。
上面三個基類都定義得很簡單,而basic_string類的實現非常復雜。不過它的設計和大多數標準庫一樣,把復雜的功能分成幾部分去實現,充分體現了模塊的低耦合。
迭代器有關的操作交給_String_iterator類去實現,元素相關的操作交給char_traits類去實現,內存分配交給allocator類去實現。

_String_iterator類的繼承關系如下圖:

探究C++中string類的實現原理以及擴展使用

這個類實現了迭代器的通用操作,比如:

reference operator*() const; pointer operator->() const _String_iterator & operator++() _String_iterator operator++(int) _String_iterator& operator--() _String_iterator operator--(int) _String_iterator& operator+=(difference_type _Off) _String_iterator operator+(difference_type _Off) const _String_iterator& operator-=(difference_type _Off) _String_iterator operator-(difference_type _Off) const difference_type operator-(const _Mybase& _Right) const reference operator[](difference_type _Off) const 

有了迭代器的實現,就可以很方便的使用算法庫里面的函數了,比如將所有字符轉換為小寫:

string s("Hello String"); transform(s.begin(), s.end(), s.begin(), tolower); 

char_traits類圖如下:

探究C++中string類的實現原理以及擴展使用

這個類定義了字符的賦值,拷貝,比較等操作,如果有特殊需求也可以重新定義這個類。

allocator類圖如下:

探究C++中string類的實現原理以及擴展使用

這個類使用new和delete完成內存的分配與釋放等操作。你也可以定義自己的allocator,msdn上有介紹哪些方法是必須定義的。

再看看basic_string類的數據成員:

_Mysize表示實際的元素個數,初始值為0;

_Myres表示當前可以存儲的最大元素個數(超過這個大小就要重新分配內存),初始值是_BUF_SIZE-1;

_BUF_SIZE是一個enum類型:

enum {  // length of internal buffer, [1, 16]   _BUF_SIZE = 16 / sizeof (_Elem) < 1 ? 1: 16 / sizeof(_Elem) }; 

從這個定義可以得出,針對char和wchar_t它的值分別是16和8。
_Bxty是一個union:

union _Bxty {  // storage for small buffer or pointer to larger one   _Elem _Buf[_BUF_SIZE];   _Elem *_Ptr; } _Bx; 

為什么要那樣定義_Bxty呢,看下面這段代碼:

_Elem * _Myptr() {  // determine current pointer to buffer for mutable string   return (_BUF_SIZE <= _Myres ? _Bx._Ptr : _Bx._Buf); }

  
這個函數返回basic_string內部的元素指針(c_str函數就是調用這個函數)。
所以當元素個數小于_BUF_SIZE時不用分配內存,直接使用_Buf數組,_Myptr返回_Buf。否則就要分配內存了,_Myptr返回_Ptr。

不過內存分配策略又是怎樣的呢?看下面這段代碼:

void _Copy(size_type _Newsize, size_type _Oldlen) {  // copy _Oldlen elements to newly allocated buffer   size_type _Newres = _Newsize | _ALLOC_MASK;   if (max_size() < _Newres)     _Newres = _Newsize; // undo roundup if too big   else if (_Newres / 3 < _Myres / 2 && _Myres <= max_size() - _Myres / 2)     _Newres = _Myres + _Myres / 2; // grow exponentially if possible   //other code } 

_ALLOC_MASK的值是_BUF_SIZE-1。這段代碼看起來有點復雜,簡單描述就是:最開始_Myres每次增加_BUF_SIZE,當值達到一定大小時每次增加一半。
針對char和wchar_t,每次分配內存的臨界值分別是(超過這些值就要重新分配):

char:15,31,47,70,105,157,235,352,528,792,1188,1782。。。wchar_t:7, 15, 23, 34, 51, 76, 114, 171, 256, 384, 576, 864, 1296, 1944。。。

重新分配后都會先將舊的元素拷貝到新的內存地址。所以當處理一個長度會不斷增長而又大概知道最大大小時可以先調用reserve函數預分配內存以提高效率。

string類占多少字節的內存空間呢?

_Container_base Debug下含有一個指針,4字節,Release下是空類,0字節。_String_val類含有一個allocator對象。string類使用默認的allocator類,這個類沒有數據成員,不過按字節對齊的原則,它占4字節。basic_string類的成員加起來是24,所以總共是32字節(Debug)或28字節(Relase)。wstring也是32或28,至于原因文中已經分析。


綜上所述:string和wstring類借助_String_iterator實現迭代器操作,都占32(Debug)或28(Release)字節的內存空間,沒有虛函數,構造和析構開銷較低,內存分配比較靈活。


擴展string類
在實際開發過程中,C++string類使用起來有很多不方便的地方,筆者根據根據這些不足簡單的擴展了這個類,如增加與數字之間的相互轉化和格式化字符串。不足的地方望指正。讀者也可以根據自己需求繼續擴展。

頭文件:exstring.h

/* Author: wuqiang Email: debugroot@126.com Description:exstring is a subclass of basic_string.It is added some userful operations,such as toUpper,toLower,toNumber,fromNumber,format,etc.It can also convert between basic_string seamlessly,which is very important for compatibility. And it is almostly a wrapper of some C++ standard library,so there should be no bugs. If you find some,please let me known.It is totally free,you can use it in any way you desire. */ #pragma once  #include <string> #include <stdarg.h> #include <algorithm> #include <sstream> #include <iomanip>  using namespace std;  #ifndef INLINE #define INLINE inline #endif //INLINE  static ios_base::fmtflags BaseFlag(int base) {   return (base == 16) ? (ios_base::hex) :      ( (base == 8) ? (ios_base::oct) : (ios_base::dec) ); }  template<class _Elem> struct ex_char_traits { };  template<> struct ex_char_traits<char> {   static INLINE int ct_vscprintf(const char* format, va_list argptr )    {      return _vscprintf(format, argptr);   }   static INLINE int ct_vstprintf_s(char* buffer, size_t numberOfElements,     const char* format, va_list argptr)    {      return vsprintf_s(buffer, numberOfElements, format, argptr);    } };  template<> struct ex_char_traits<wchar_t> {   static INLINE int ct_vscprintf(const wchar_t* format, va_list argptr )    {      return _vscwprintf(format, argptr);   }   static INLINE int ct_vstprintf_s(wchar_t* buffer, size_t numberOfElements,     const wchar_t* format, va_list argptr)    {      return vswprintf_s(buffer, numberOfElements, format, argptr);    } };  template<class _Elem, class _Traits, class _Ax, class Type> Type ConvertToNumber(basic_stringstream<_Elem, _Traits, _Ax>& ss,             Type t, int base) {   ss.setf(BaseFlag(base), ios_base::basefield);   ss >> t;   return t; }  template<class _Elem, class _Traits, class _Ax> float ConvertToNumber(basic_stringstream<_Elem, _Traits, _Ax>& ss,             float t, int/*ignore base*/) {   ss >> t;   return t; }  template<class _Elem, class _Traits, class _Ax> double ConvertToNumber(basic_stringstream<_Elem, _Traits, _Ax>& ss,              double t, int/*ignore base*/) {   ss >> t;   return t; }  template<class _Elem, class _Traits, class _Ax, class _ExTraits> class basic_exstring : public basic_string<_Elem, _Traits, _Ax> { public:   typedef basic_exstring<_Elem, _Traits, _Ax, _ExTraits> _Myt;   typedef basic_string<_Elem, _Traits, _Ax> _Mybase;  #pragma region "constructor"    //所有構造函數的行為同basic_string    explicit INLINE _Myt(const _Ax& al = _Ax())     :_Mybase(al)   {   }   INLINE _Myt(const _Myt& rhs)     :_Mybase(rhs)   {   }   INLINE _Myt(const _Myt& rhs, size_type pos, size_type n,const _Ax& al = _Ax())     :_Mybase(rhs, pos, n, al)   {   }   INLINE _Myt(const _Elem *s, size_type n, const _Ax& al = _Ax())     :_Mybase(s, n, al)   {   }   INLINE _Myt(const _Elem *s, const _Ax& al = _Ax())     :_Mybase(s, al)   {   }   INLINE _Myt(size_type n, _Elem c, const _Ax& al = _Ax())     :_Mybase(n, c, al)   {   }   INLINE _Myt(const_iterator first, const_iterator last,const _Ax& al = _Ax())     :_Mybase(first, last, al)   {   }    //string(wstring)轉化為exstring(exwstring)   INLINE _Myt(const _Mybase& base)     :_Mybase(base)   {    } #pragma endregion //constructor   #pragma region "general operation"    //所有字符轉為大寫,改變自身   _Myt& toUpper()   {     transform(begin(), end(), begin(), toupper);     return *this;   }    //所有字符轉為大寫,不改變自身   _Myt toUpper() const   {     _Myt s;     transform(begin(), end(), s.begin(), toupper);     return s;   }    //所有字符轉為小寫,改變自身   _Myt& toLower()   {     transform(begin(), end(), begin(), tolower);     return *this;   }    //所有字符轉為大寫,不改變自身   _Myt toLower() const   {     _Myt s(_Mysize, _Elem());     transform(begin(), end(), s.begin(), tolower);     return s;   }    //將所有oldStr替換為newStr   _Myt& replace(const _Myt& oldStr, const _Myt& newStr)   {     if (oldStr.empty())       return *this;     size_type index;     while ( (index = find(oldStr)) != npos )       _Mybase::replace(index, oldStr.size(), newStr);     return *this;   }    //刪除左邊所有包含在target中的字符   _Myt& trimLeft(const _Myt& target)   {     while (!empty() && (target.find(*begin()) != npos))       erase(begin());     return *this;   }    //刪除右邊所有包含在target中的字符   _Myt& trimRight(const _Myt& target)   {     while (!empty() && target.find(*rbegin()) != npos)       erase(--end());     return *this;   }    //返回左邊count個字符,count大于總長度則返回整個字符串   _Myt left(size_type count) const   {     return substr( 0, count );   }    //返回右邊count個字符,count大于總長度則返回整個字符串   _Myt right(size_type count) const   {     return substr( _Mysize < count ? 0 : _Mysize - count );   }    //忽略大小寫判斷兩個字符串是否相等   int compareNoCase(const _Myt& rhs) const   {     return toLower().compare(rhs.toLower());   }    //判斷字符串是否以制定字符串開頭   bool beginWith(const _Myt& rhs) const   {     return find(rhs) == size_type(0);   }    //判斷字符串是否以制定字符串結尾   bool endWith(const _Myt& rhs) const   {     if(rhs.size() > _Mysize)       return false;     return compare(_Mysize - rhs.size(), rhs.size(), rhs) == 0;   } #pragma endregion //general operation   #pragma region "convert between numbers"      //將字符串轉為數字   //base:進制數??梢詾?,10,16,如果其它值則強制為10。浮點數則忽略此參數   template<typename T>   T toNumber (int base = 10) const   {     T t = T();     basic_stringstream<_Elem, _Traits, _Ax> ss(_Myptr());     return ConvertToNumber<_Elem, _Traits, _Ax>(ss, t, base);   }    //將整數轉化為字符串   //base:進制數。可以為8,10,16,如果其它值則強制為10   template<typename T>   static _Myt fromNumber ( T number, int base = 10 )   {     basic_stringstream<_Elem, _Traits, _Ax> ss;     ss.setf(BaseFlag(base), ios_base::basefield);     ss << number;     return ss.str();   }    //將float轉化為字符串   //f:格式化參數??梢詾?#39;f','e','E','g','G'。'f'為定點數,'e'或'E'表示科學計數法   // 'g'或‘G'表示格式化為定點數或科學計數法,看哪一個表示方便。   //prec:小數點后的位數(定點數表示法)或總的有效位數(科學計數法)   static _Myt fromNumber ( float number, _Elem f = _Elem('g'), int prec = 6 )   {     return fromNumber(static_cast<double>(number), f, prec);   }    //將double轉化為字符串,參數解釋同上   static _Myt fromNumber ( double number, _Elem f = _Elem('g'), int prec = 6 )   {     basic_stringstream<_Elem, _Traits, _Ax> ss;     ss << setprecision(prec);     if ( _Traits::eq(f, _Elem('f')) )       ss << setiosflags(ios_base::fixed);     else if ( _Traits::eq(f, _Elem('e')) || _Traits::eq(f, _Elem('E')) )       ss << setiosflags(ios_base::scientific);     ss << number;     return ss.str();   } #pragma endregion //convert between numbers   #pragma region "format string"    //將szFormat格式化為字符串,參數解釋同sprintf   void format(const _Elem* szFormat, ...)   {     if(!szFormat)       return;     va_list argList;     va_start(argList, szFormat);     formatV(szFormat, argList);     va_end(argList);   }    //將szFormat格式化為字符串,參數解釋同sprintf   void formatV(const _Elem* szFormat, va_list argList)   {     if(!szFormat)       return;     int nLength = _ExTraits::ct_vscprintf(szFormat, argList);     if(nLength < 0)       return;     resize(nLength);     _ExTraits::ct_vstprintf_s(_Myptr(), nLength + 1, szFormat, argList);     va_end(argList);   } #pragma endregion //format string };  typedef basic_exstring<char, char_traits<char>,    allocator<char>, ex_char_traits<char> > exstring;  typedef basic_exstring<wchar_t, char_traits<wchar_t>,    allocator<wchar_t>, ex_char_traits<wchar_t> > exwstring; 

使用舉例:

#include <iostream> #include <tchar.h> #include "exstring.h"  #ifdef _UNICODE typedef exwstring tstring; #define tcout wcout #else typedef exstring tstring; #define tcout cout #endif //_UNICODE  int main(int argc, char* argv[]) {   tstring s(_T("/t Hello ExString/r/n"));   tcout << _T("result of triming left:") << s.trimLeft(_T("/t ")) << endl;   tcout << _T("result of triming right:") << s.trimRight(_T("/r/n")) << endl;   tcout << _T("result of compare") << s.compareNoCase(_T("hello exstring")) << endl;   tcout << _T("result of converting to upper:") << s.toUpper() << endl;   tcout << _T("result of converting to lower:") << s.toLower() << endl;    tcout << _T("the left 5 chars:") << s.left(5) << endl;   tcout << _T("the right 8 chars:") << s.right(8) << endl;   tcout << _T("result of appending:") << s.append(_T(",exstring is practical")) << endl;   tcout << _T("result of replacing:") << s.replace(_T("exstring"), _T("Exstring")) << endl;    s.format(_T("sizeof(%s) is %d(0x%x)"), _T("exstring"), sizeof(exstring), sizeof(exstring));   tcout << _T("result of formating:") << s << endl;    tcout << tstring(_T("0xFF")).toNumber<int>(16) << endl;   tcout << tstring(_T("-1")).toNumber<unsigned __int64>() << endl;   tcout << tstring(_T("12.3456789")).toNumber<float>() << endl;    tcout << tstring::fromNumber(255) << endl;   tcout << _T("0x") << tstring::fromNumber(__int64(-1), 16).toUpper() << endl;   tcout << tstring::fromNumber(12.3456789, _T('f'), 4) << endl;   tcout << tstring::fromNumber(12.3456789, _T('E'), 4) << endl;    return 0; } 

輸出:

探究C++中string類的實現原理以及擴展使用



發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
91精品久久久久久久久久入口| 亚洲男人第一网站| 91禁国产网站| 亚洲a级在线播放观看| 国产精品亚洲аv天堂网| 久久男人的天堂| 亚洲黄在线观看| 中文字幕精品—区二区| 亚洲一区二区三区久久| 日韩中文有码在线视频| 国产日韩视频在线观看| 亚洲乱码国产乱码精品精天堂| 国产精品91视频| 色伦专区97中文字幕| 久久国产精品网站| 欧美日韩免费区域视频在线观看| 国产日韩精品在线播放| 一本一本久久a久久精品综合小说| 国产欧美日韩中文| 国产成人精品视频在线观看| 国产亚洲精品久久久久久| 成人精品福利视频| 亚洲香蕉成人av网站在线观看| 久久不射热爱视频精品| 精品国内自产拍在线观看| 日韩在线观看免费网站| 26uuu久久噜噜噜噜| 国产精品久久久久国产a级| 久久成年人免费电影| 亚洲精品国产电影| 亚洲品质视频自拍网| 欧美激情按摩在线| 夜夜嗨av一区二区三区四区| 久久久久久久久久久成人| 国产一区二区在线免费视频| 一区二区三区国产在线观看| 欧美电影在线观看高清| 欧美日韩亚洲精品一区二区三区| 国语自产精品视频在免费| 91免费在线视频| 亚洲日本aⅴ片在线观看香蕉| 日韩欧美国产网站| 久久中文字幕在线| 欧美夫妻性视频| 欧美极品美女视频网站在线观看免费| 日韩av电影中文字幕| 久久人人爽人人爽人人片av高请| 欧美激情中文字幕在线| 欧美精品18videosex性欧美| 黄色91在线观看| 国产伊人精品在线| 国产伦精品一区二区三区精品视频| 亚洲v日韩v综合v精品v| 精品夜色国产国偷在线| 另类专区欧美制服同性| 青青草99啪国产免费| 日本亚洲欧洲色α| 久久天堂av综合合色| 国产亚洲精品激情久久| 久久免费观看视频| 中文字幕在线看视频国产欧美在线看完整| 欧美另类在线观看| 欧美另类极品videosbestfree| 国产精品久久中文| 日韩在线不卡视频| 亚洲系列中文字幕| 欧美性猛交xxxx偷拍洗澡| 国产精品美女无圣光视频| 欧美成人在线免费| 欧美激情在线观看视频| 国产不卡av在线免费观看| 国内精品免费午夜毛片| 在线观看成人黄色| 欧美肥老妇视频| 日本久久久久久| 色青青草原桃花久久综合| 日韩欧美在线免费| 国产欧美日韩精品丝袜高跟鞋| 亚洲欧洲在线免费| 国产精品久久av| 日韩一二三在线视频播| 国产精品99久久久久久白浆小说| 都市激情亚洲色图| xxx一区二区| 亚洲综合成人婷婷小说| 亚洲va码欧洲m码| 欧美日韩国产一区二区三区| 亚洲美女久久久| 国产精品自拍视频| 96sao精品视频在线观看| 亚洲日韩欧美视频一区| 日韩欧美亚洲国产一区| 精品国产乱码久久久久久天美| 久久久视频免费观看| 日本精品va在线观看| 亚洲视频电影图片偷拍一区| 亚洲一品av免费观看| 国产欧美亚洲视频| 国产美女久久精品| 精品日韩中文字幕| 91精品国产高清自在线看超| 国产精品久久久久久婷婷天堂| 欧美大片在线看免费观看| 亚洲网址你懂得| 亚洲影影院av| 日韩欧美视频一区二区三区| 欧美性xxxx极品高清hd直播| 日韩在线资源网| 色av吧综合网| 欧美丝袜一区二区三区| 日本一区二三区好的精华液| 日韩av网站在线| 亚洲第一中文字幕在线观看| 亚洲成人动漫在线播放| 亚洲天堂av在线免费| 欧美大片欧美激情性色a∨久久| 国产91成人video| 日韩av片永久免费网站| 91成人精品网站| 亚洲色图欧美制服丝袜另类第一页| 在线视频免费一区二区| 久久免费福利视频| 国模gogo一区二区大胆私拍| 久久99精品久久久久久琪琪| 成人黄色免费在线观看| 韩剧1988免费观看全集| 91黑丝在线观看| 国产亚洲人成网站在线观看| 国产成人精品日本亚洲| 久久免费福利视频| 成人精品视频在线| 欧美性猛交xxxx久久久| 亚洲最大成人在线| 久久人人看视频| 不卡伊人av在线播放| 精品一区二区三区三区| 亚洲精品日韩欧美| 91色精品视频在线| 欧美性xxxxx极品| 2024亚洲男人天堂| 国产精品96久久久久久又黄又硬| 久久亚洲私人国产精品va| 国产精品视频一| 国产精品视频区| 国产精品亚洲一区二区三区| 亚洲美女www午夜| 在线看福利67194| 亚洲**2019国产| 韩国欧美亚洲国产| 日韩精品视频三区| 日韩午夜在线视频| 成人做爽爽免费视频| 国产伦精品一区二区三区精品视频| 日韩成人在线网站| 欧洲永久精品大片ww免费漫画| 1769国产精品| 亚洲一区二区久久久久久久| 性夜试看影院91社区| 国产视频在线观看一区二区| 91精品在线观看视频| 国产精品极品尤物在线观看| 97婷婷大伊香蕉精品视频| 福利一区福利二区微拍刺激| 欧美性xxxx极品hd欧美风情|