getline原始碼簡析

來源:互聯網
上載者:User

這個代碼的注釋參考了許多網友的心得,也加了一些我自己的體會,供後來者參考。

C++標準庫basic_istream類的getline成員函數有兩個版本

basic_istream<Elem, Tr>& getline(      char_type *_Str,      streamsize _Count);basic_istream<Elem, Tr>& getline(     char_type *_Str,      streamsize _Count,       char_type _Delim);

第一個參數為使用者提供的字元數組首地址,第二個為數組長度,第三個為字串分隔符號。

第一個版本的成員函數的一個實現為

typedef basic_istream<_Elem, _Traits> _Myt;typedef basic_ios<_Elem, _Traits> _Myios;_Myt& getline(_Elem *_Str, streamsize _typedef basic_istream<_Elem, _Traits> _Myt;Count){// get up to _Count characters into NTCS, discard newline   return (getline(_Str, _Count, _Myios::widen('\n')));}

可見它最終還是調用了第二個版本的getline,只是把分隔字元設成了常見的斷行符號而已,所以下面我們來重點分析下第二個成員函數的實現。

_Myt& getline(_Elem *_Str, streamsize _Count, _Elem _Delim) {// get up to _Count characters into NTCS, discard _Delim  _DEBUG_POINTER(_Str);    //判斷傳入指標的合法性 ios_base::iostate _State = ios_base::goodbit;   _Chcount = 0; //從輸入資料流中讀取的字元數 const sentry _Ok(*this, true); /*註:上面這句很關鍵,它關係到下面的if是否執行,也就是是否讀輸入資料流。這句從文法上看,是 sentry是一個class, _Ok是sentry類的一個const對象,構造這個對象時需要傳入兩個參數 第一個是流對象自身的引用,第二個表示對空白字元(如空格、定位字元)的處理方式,為true時意味著不忽略空白字元,即一個字元一個字元的從輸入資料流中提取。 */  if (_Ok && 0 < _Count)    /* **************************************************************************   * sentry類內部重載了一個類型轉換運算子,它把sentry類的執行個體轉換成了一個bool運算式。   * 這個運算式返回sentry類的私人成員_Ok的值。   bool sentry::operator bool() const   * {// test if _Ipfx succeeded*return (_Ok);   * }   * _Ok這個成員的值由sentry類的建構函式   * 在初始化時設定,設定的過程比較麻煩,這裡不做贅述(其實我也沒看十分明白)。   * 但可以肯定的是,當輸入資料流的狀態是正常時,這個成員的值也是true,   * 反之,則是false。    *    * _Count是調用者傳入的第二個參數,這裡用做迴圈計數器的初值,以後每讀一個字元,   * _Count的值會減一。   ******************************************************************************/ {    // state okay, use facet to extract     int_type _Metadelim = _Traits::to_int_type(_Delim);     int_type _Meta = _Myios::rdbuf()->sgetc();//從輸入資料流讀一個字元     for (; ; _Meta = _Myios::rdbuf()->snextc()) //snextc()從輸入資料流中讀取下一個字元if (_Traits::eq_int_type(_Traits::eof(), _Meta))               {// end of file, quit                _State |= ios_base::eofbit;  break;     }//註:遇到檔案尾,getline結束  else if (_Meta == _Metadelim) { // got a delimiter, discard it and quit  ++_Chcount;    //讀取字元數+1 _Myios::rdbuf()->sbumpc(); /*註:上面這句把結束符讀掉了,如果不指定結束符,那就是把'\n'讀掉了。  但斷行符號符本身並沒有拷貝到緩衝區中, 這樣下次的讀操作將從斷行符號符後面的第一個字元開始, */ break;  }/* 註:遇到結束符,getline結束,注意這裡的順序,它是先判斷是否遇到結束符,後判斷是否讀入了指定個數的。 */ else if (--_Count <= 0)  {// buffer full, quit  _State |= ios_base::failbit;  break;  } //註:讀到了指定個數,執行到這裡已經隱含了在指定個數的最後一位仍然不是結束符, //因此該部分將輸入資料流狀態置為了錯誤。 //這直接導致了接下來的getline(或者get)以及>>運算子等讀操作都不能正確執行)  else { // got a character, add it to string  ++_Chcount;  //讀取字元數加1 *_Str++ = _Traits::to_char_type(_Meta);  }//註:這一分支將讀取到的單個字元拷貝到緩衝區中 }  *_Str = _Elem();  // /* add terminating null character /*註:前面這句為字串加入了終止符'\0' 因為_Elem()構造了一個ascii碼為0的字元對象*/ _Myios::setstate(_Chcount == 0 ? _State | ios_base::failbit : _State); /*註:如果沒有讀入任何字元,要保持執行這一次getline之前的輸入資料流狀態, 否則根據這一次getline執行的情況,設定輸入資料流為相應狀態。 */ return (*this);   //返回輸入資料流對象本身}  

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.