ifstream::unget()が失敗します。はMSの実施バギーは自分のコードの誤?
-
26-09-2019 - |
質問
昨日見奇グ近くで見ると、グラデーションコードというものがテキストから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 unget()
位置にします。できますので安全につい unget()
呼び出しの後に、あなたの get()
.をご利用いただきます peek()
の入力バッファが空の場合には、 underflow()
発の実施をクリアし、バッファおよび負荷分のデータです。ご注意 peek()
い電流入力の位置でポイントの先頭にバッファです。を行なったとき、 unget()
を実施しようとし減少電流入力位置がでの初めにバッファーなので失敗します。
もちろんこれは実装に依存します。ストリームにバッファを保持しますバックアップイメージで失敗する場合があり、時にはいません。私が知る限りではmicrosoft社の実店舗ャbasic_filebuf場の指定によりバッファを明示的に)に依存してお <cstdio>
内部バッファリング(ちなみに、その理由としMVS iostreamsています。品質の実装では荷重のバッファからのファイルの場合 unget()
失敗します。しかし、その先には、が必要です。
して固定コードは必要ありませんよ unget()
位置にします。ご本当に必要なプを通し、ストリームとストリームを保障するようなunget()い(見が進みました。Iostreams).また、コードだ投稿はナンセンスです。ろうとし unget()
その get()
ます。なぜですか?