2012-02-08 6 views
3

この小さなカスタムゲットライン関数は、異なる行末の処理に関する質問にanswerとして与えられました。C++:std :: istreamまたはsentryラップアラウンドで異常な動作

この関数は、2日前に編集されて各行の先頭の空白をスキップしないようにするまで機能しました。しかし、編集後、プログラムは無限ループに入ります。誰かが、我々はしないように指定した場合、プログラムが無限ループし、なぜ私が説明助けてください

std::istream::sentry se(is, true); // With this line enabled, the program goes 
            // into infinite loop inside the while loop 
            // of the main function. 

:これまで

std::istream::sentry se(is); // When this line is enabled, the program executes 
           // correctly (no infinite loop) but it does skip 
           // leading white spaces 

:コードに行われる唯一の変化は、このから変更されました。この次の行でした空白をスキップしますか?ここで

は...

std::istream& safeGetline(std::istream& is, std::string& t) 
{ 
    t.clear(); 

    // The characters in the stream are read one-by-one using a std::streambuf. 
    // That is faster than reading them one-by-one using the std::istream. 
    // Code that uses streambuf this way must be guarded by a sentry object. 
    // The sentry object performs various tasks, 
    // such as thread synchronization and updating the stream state. 

    std::istream::sentry se(is, true); 
    std::streambuf* sb = is.rdbuf(); 

    for(;;) { 
     int c = sb->sbumpc(); 
     switch (c) { 
     case '\r': 
      c = sb->sgetc(); 
      if(c == '\n') 
       sb->sbumpc(); 
      return is; 
     case '\n': 
     case EOF: 
      return is; 
     default: 
      t += (char)c; 
     } 
    } 
} 

そしてここでは、テストプログラムの完全なプログラムです。

int main() 
{ 
    std::string path = "end_of_line_test.txt" 

    std::ifstream ifs(path.c_str()); 
    if(!ifs) { 
     std::cout << "Failed to open the file." << std::endl; 
     return EXIT_FAILURE; 
    } 

    int n = 0; 
    std::string t; 
    while(safeGetline(ifs, t)) //<---- INFINITE LOOP happens here. <---- 
     std::cout << "\nLine " << ++n << ":" << t << std::endl; 

    std::cout << "\nThe file contains " << n << " lines." << std::endl; 
    return EXIT_SUCCESS; 
} 

私は、関数の先頭に次の行を追加しようとしましたが、それは作られました違いはありません...プログラムはメイン関数のwhileループで無限にループしていました。

"1234" // A line with leading white spaces 
"5678" // A line without leading white spaces 
+0

@templatetypedef Windows上で動作するVisual C++に最新バージョンのコマンドラインコンパイラを使用しています。32ビット。もし私がセンチラインを "std :: istream :: sentry se(is);"に変更したら、プログラムは動作しますが、私がそれを "std :: istream :: sentry se(is、true);"に戻すと、プログラムがクラッシュします。あなたのテストファイルでは、いずれの行にも先頭にスペースがありますか? –

+0

具体的なクラッシュは何ですか?スタックトレースを取得できますか? – templatetypedef

+0

クラッシュを示すためにwhileループ内の行を変更しました。私は、tの内容について行番号と数字のゼロを示す無限のプリントアウトを得る。私はスタックトレース(初心者、申し訳ありません)を行う方法がわかりません。 –

答えて

6

問題はsafeGetLineは決してストリームのためeof()状態を設定していないということです。

is.setf(0, std::ios::skipws); 

ファイルend_of_line_test.txtは以下の2行を含むテキストファイルです。

std::istream::sentry se(is);を使用すると、となります。は、空白の読み取りを試み、ファイルの最後にいることを検出します。空白を探しないように頼んだら、これは決して起こりません。

この機能のEOF条件にis.setstate(ios_base::eofbit)を追加する必要があります。

+0

お返事ありがとうございました。私は 'を追加しました。getline関数の 'case EOF:'と 'return is;'の間に 'setstate(ios_base :: eofbit)'を追加します。ただし、プログラムは1行の印刷後に停止します。毎回実行するように関数の初めにストリーム状態ビットをクリアする必要がありますか?それとも危険ですか? –

+0

EOFケースは '' \ n''ケースから分離する必要があります。 –

+0

@Bo ...ありがとうございました。あなたは問題を解決しました。完璧に!!!!!!私は今、私が探していた振る舞いを得ることができます。 –

関連する問題