コンパイラを gcc-4.4 から gcc-4.8 にアップグレードしましたが、次の (誤った) 仮定に起因して、1 つのプロジェクトが惨めに失敗しました。
#include <sstream>
#include <assert.h>
int main()
{
using namespace std;
istringstream iScan;
int num;
//iScan.unsetf(std::ios::skipws);
iScan.str("5678");
iScan >> num;
assert(iScan.tellg() == istringstream::pos_type(4));
assert(!iScan.fail());
assert(!iScan.good());
assert(iScan.eof());
assert(num == 5678);
assert(false && "We passed the above assertions.");
return 0;
}
gcc-4.4 では、関連するアサーションがパスします。gcc-4.8 では、tellg() は -1 を返し、fail() は !false を返します。これは明らかに eof にヒットしたためです。
私のターゲットは、Qt 5.1 (gcc-4.8) に同梱されている MinGW 32 ビットです。
質問:
- N3168またはその他によると、古い動作は本当に間違っていますか? (その他の?)
- グローバルで信頼性が高く、言語に依存しない回避策はありますか? (そうではないと思います。)
- バージョンにまたがるグローバルで信頼性の高い gcc の回避策はありますか?
- 上記の unsetf(skipws) を実行しても、gcc-4.8 では動作しません。それは不正行為ではないでしょうか?
さらに、さまざまなオンライン コンパイラが異なる動作をします。それは彼らのlibの機能ですか?
- gcc-4.7.2 であると主張するcompileonlineは、他のソースが 4.6 で動作が変更されたと言っているにもかかわらず、それを許可します。
- stack-crooked、gcc-4.8 は新しい動作を示し、unsetf(skipws) は効果がないようです。
- コードパッドはそれを可能にします。バージョンは言えません。
その他の類似するが重複しない質問:
これらの仮定がすべて実行されているコード本体は、大規模です。
更新: これが答えの重要な部分です。これは、すべてのバージョン、すべてのコンパイラで機能するはずです:
// istream::tellg() is unreliable at eof(): works w/gcc-4.4, doesn't w/gcc-4.8.
#include <sstream>
#include <assert.h>
using namespace std;
typedef istream::pos_type pos_type;
pos_type reliable_tellg(istream &iScan)
{
bool wasEOF = iScan.eof();
if (wasEOF)
iScan.clear(iScan.rdstate() & ~ios::eofbit); // so tellg() works.
pos_type r = iScan.tellg();
if (wasEOF)
iScan.clear(iScan.rdstate() | ios::eofbit); // restore it.
return r;
}
int main()
{
istringstream iScan;
int num, n2;
//iScan.unsetf(std::ios::skipws);
iScan.str("5678");
assert(!iScan.eof() && !iScan.fail()); // pre-conditions.
assert(reliable_tellg(iScan) == pos_type(0));
iScan >> num;
assert(!iScan.fail());
assert(reliable_tellg(iScan) == pos_type(4));
assert(iScan.eof());
assert(reliable_tellg(iScan) == pos_type(4)); // previous calls don't bungle it.
assert(num == 5678);
iScan >> n2; // at eof(), so this should fail.
assert(iScan.fail());
assert(reliable_tellg(iScan) == pos_type(-1)); // as expected on fail()
assert(iScan.eof());
assert(false && "We passed the above assertions.");
return 0;
}