質問

昨日見奇グ近くで見ると、グラデーションコードというものがテキストからifstreamとtokenizesます。このコードが実際に失敗したい件数(取止め)を取得します)/peek()の呼び出しのトークン"/*".場合にはトークンは、ストリームunget()が呼び出されることで、次の方法は、ストリームからトークンである。

時には一見によってのみファイルの長さは、unget()を呼び出しは失敗します。内部的に呼びかけられていpbackfail()を返しまEOF.しかし、清算のストリームの状態で、喜んでいただけました読み取り文字でなEOF..

掘、こちらのフルコードを簡単に再現性の問題:

#include <iostream>
#include <fstream>
#include <string>

  //generate simplest string possible that triggers problem
void GenerateTestString( std::string& s, const size_t nSpacesToInsert )
{
  s.clear();
  for( size_t i = 0 ; i < nSpacesToInsert ; ++i )
    s += " ";
  s += "/*";
}

  //write string to file, then open same file again in ifs
bool WriteTestFileThenOpenIt( const char* sFile, const std::string& s, std::ifstream& ifs )
{
  {
    std::ofstream ofs( sFile );
    if( ( ofs << s ).fail() )
      return false;
  }
  ifs.open( sFile );
  return ifs.good();
}

  //find token, unget if found, report error, show extra data can be read even after error 
bool Run( std::istream& ifs )
{
  bool bSuccess = true;

  for( ; ; )
  {
    int x = ifs.get();
    if( ifs.fail() )
      break;
    if( x == '/' )
    {
      x = ifs.peek();
      if( x == '*' )
      {
        ifs.unget();
        if( ifs.fail() )
        {
          std::cout << "oops.. unget() failed" << std::endl;
          bSuccess = false;
        }
        else
        {
          x = ifs.get();
        }
      }
    }
  }

  if( !bSuccess )
  {
    ifs.clear();
    std::string sNext;
    ifs >> sNext;
    if( !sNext.empty() )
      std::cout << "remaining data after unget: '" << sNext << "'" << std::endl;
  }

  return bSuccess;
}

int main()
{
  std::string s;
  const char* testFile = "tmp.txt";
  for( size_t i = 0 ; i < 12290 ; ++i )
  {
    GenerateTestString( s, i );

    std::ifstream ifs;
    if( !WriteTestFileThenOpenIt( testFile, s, ifs ) )
    {
      std::cout << "file I/O error, aborting..";
      break;
    }

    if( !Run( ifs ) )
      std::cout << "** failed for string length = " << s.length() << std::endl;
  }
  return 0;
}

のプログラム失敗した場合、文字列の長さが近く、代表的な複数=の2buffersizes4096,8192,12288、"わらびもち"をここで出力:

oops.. unget() failed
remaining data after unget: '*'
** failed for string length = 4097
oops.. unget() failed
remaining data after unget: '*'
** failed for string length = 8193
oops.. unget() failed
remaining data after unget: '*'
** failed for string length = 12289

この場合の動作確認はWindows XPおよび7両編ット/リモードでは、動的/静的なランタイム時において、両32bitと64bitシステム統、VS2008、デフォルトのコンパイラ/リンカーオプション問題ないかを試験する場合そのgcc4.4.5、64bit版のDebianシステム。

ご質問:

  1. できるその他の人が試験ください。ことに感謝していか積極的なコラボレーション形式です。
  2. はありま ることが正しくないのコードの原因となる問題のないこと)
  3. 又はコンパイラフラグがトリガーのこの行動は?
  4. すべてのパーサコードはむしろ重要なのは、出来る限り多くの試験がよくオフコースこの問題は見つかりませんでしたテストコードです。きっと極端なテストケース、その場合、どうすればよいでしょうか。どのようにしたら良いですか来予測することが問題なのか。
  5. これは本当にバグがない最高の報告書です。
役に立ちましたか?

解決

何が正しくないのコードの原因となる問題のないこと)

そうです。標準ストリームを必要として少なくとも1 unget() 位置にします。できますので安全につい unget() 呼び出しの後に、あなたの get().をご利用いただきます peek() の入力バッファが空の場合には、 underflow() 発の実施をクリアし、バッファおよび負荷分のデータです。ご注意 peek() い電流入力の位置でポイントの先頭にバッファです。を行なったとき、 unget() を実施しようとし減少電流入力位置がでの初めにバッファーなので失敗します。

もちろんこれは実装に依存します。ストリームにバッファを保持しますバックアップイメージで失敗する場合があり、時にはいません。私が知る限りではmicrosoft社の実店舗ャbasic_filebuf場の指定によりバッファを明示的に)に依存してお <cstdio> 内部バッファリング(ちなみに、その理由としMVS iostreamsています。品質の実装では荷重のバッファからのファイルの場合 unget() 失敗します。しかし、その先には、が必要です。

して固定コードは必要ありませんよ unget() 位置にします。ご本当に必要なプを通し、ストリームとストリームを保障するようなunget()い(見が進みました。Iostreams).また、コードだ投稿はナンセンスです。ろうとし unget() その get() ます。なぜですか?

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top