我将编译器从gcc-4.4升级到gcc-4.8,并且一个项目因以下(错误)假设而失败:
#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位。
问题:
此外,各种在线编译器提供不同的行为。这是他们的lib的功能吗?
其他类似但不重复的问题:
这些假设贯穿全部的代码体很大。
更新:这是答案的关键部分,应该适用于所有版本,所有编译器:
// 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;
}
答案 0 :(得分:1)
您似乎期望的行为可能是错误的。两者都是C ++ 11
和C ++ 03用{Behaves as a}开始tellg
的描述
无格式输入功能[...]“。”无格式输入
函数“从构造sentry
对象开始,并且将会
失败,什么也不做,并返回失败状态,如果
sentry
对象转换为false
。和sentry
对象
如果false
已设置,则会转换为eofbit
。
关于是否阅读,标准略显不清楚
number设置eofbit
,但只是稍微设置{
信息分散在几个不同的部分)。
基本上,当输入数值时,流(实际上,
num_get
facet)必须提前读取一个字符,以便
知道号码的终点。在你的情况下,它将看到结束
发生这种情况时的文件,因此将设置eofbit
。所以你的
第一个assert
将失败,并且符合实施。
人们可以很容易地认为这是标准中的缺陷,或者 无意的。一些实现很容易想象 做出明智的事(这是你所期待的), 也许是因为原来的实现者没有意识到 标准中的全部含义(或无意识地将其视为 他们认为应该阅读)。我猜这就是 g ++的情况,当他们意识到他们的行为是 不符合要求,他们修好了。
至于解决方案......我不确定真正的问题是什么,
你正试图解决这个问题。但我想如果你
清除tellg
之前的错误位,它应该工作。 (的
当然,iScan.good()
将是true
,iScan.eof()
false
。但这真的很重要吗?)一定要检查
在你清除之前,提取实际上已成功
状态。