C++ 为什么这个没有设置错误标志的文件流无法读取,除非我执行tellg()?

C++ 为什么这个没有设置错误标志的文件流无法读取,除非我执行tellg()?,c++,c++11,fstream,c++03,libstdc++,C++,C++11,Fstream,C++03,Libstdc++,我有一个fstream,它似乎进入了幻象故障状态,即使检查它(通过转换为bool)没有显示任何错误标志。后续读取失败,这是意外的 #include <fstream> #include <iostream> #include <cassert> int main() { const unsigned int SAMPLE_COUNT = 2; // Setup - create file with two "samples"; each s

我有一个fstream,它似乎进入了幻象故障状态,即使检查它(通过转换为
bool
)没有显示任何错误标志。后续读取失败,这是意外的

#include <fstream>
#include <iostream>
#include <cassert>

int main()
{
    const unsigned int SAMPLE_COUNT = 2;

    // Setup - create file with two "samples"; each sample has a double and a float
    {
        std::ofstream ofs("/tmp/ffs", std::ios::binary);

        const double colA[SAMPLE_COUNT] = {  1.0,    2.0 };
        const float  colB[SAMPLE_COUNT] = { 42.0,  100.0 };

        for (size_t i = 0; i < SAMPLE_COUNT; i++) {
            ofs.write((char*)&colA[i], sizeof(colA[i]));
            ofs.write((char*)&colB[i], sizeof(colB[i]));
        }
    }

    // Actual testcase
    {
        std::fstream fs("/tmp/ffs", std::ios::binary | std::ios::out | std::ios::in);
        assert(fs);

        unsigned int sample_n = 0;
        while (true) {
            double a;
            fs.read((char*)&a, sizeof(a));

            if (!fs) {
                std::cerr << "No more samples\n";
                break;
            }

            std::cerr << "Sample " << (++sample_n) << " first column = " << a << '\n';


            // Read column B
            float b;
            fs.read((char*)&b, sizeof(b));
            assert(fs);
            std::cerr << "Current value second column = " << b << '\n';

            // Multiply it by two and write back
            b *= 2;
            fs.seekp(-sizeof(b), std::ios::cur);
            fs.write((char*)&b, sizeof(b));
            assert(fs);

            #ifdef DO_THE_TELLG
                // Unless I do this, the `fs.read` on the next iteration fails!
                // So the loop ends, and I get only the first sample transformed in my file.
                fs.tellg();
            #endif
        }
    }

    // Inspection - should see values 84 and 200, but see 84 and 100 instead.
    {
        std::ifstream ifs("/tmp/ffs", std::ios::binary);

        std::cerr << "All values at end:\n";
        for (size_t i = 0; i < SAMPLE_COUNT; i++) {

            double a;
            float  b;

            ifs.read((char*)&a, sizeof(a));
            ifs.read((char*)&b, sizeof(b));

            std::cerr << a << '\t' << b << '\n';
        }

        assert(ifs);
    }
}
如果对其执行
tellg()
tellp()
操作,则后续读取成功,因此循环不会过早结束,第二个样本也会乘以2,以生成
200

这仅在以下环境中发生:

  • CentOS 6 x86_64,通用条款4.4.7
  • CentOS 6 x86_64,GCC 4.8.2(通过devtoolset-2)
我在以下位置获得了预期的行为,无论有无
tellg()
/
tellp()

  • CentOS 7
(如果列出的编译器同时支持C++03和C++11,我已经在这两种编译器下进行了尝试,没有发现任何差异。)

我的程序有UB吗?或者,这是我需要解决的libstdc++错误吗?



更新:好的,那么。但是Dietmar没有说明这是标准强制的还是libstdc++错误。对我来说,这看起来像是,但这是
解决的
/
WONTFIX
,那么为什么我的程序在Coliru和CentOS 7下会像预期的那样工作呢?理想情况下,在实施此解决方案之前,我希望能够更准确地掌握正在发生的事情。

这是标准要求。请参阅@n.m.:“因此,您的stream.seekp(1)解决方案(该解决方案已移交给C fseek)是正确的。”seekp的工作方式是否强制要求如此?那么,它是如何在CentOS 7上工作的呢?公认的答案是GNUC库没有这个限制,但这不是我在CentOS 6上的经验。所以现在我更糊涂了!关于glibc的说法可能是正确的,也可能是错误的,也可能只是指一些glibc版本。我从未在文档中看到过它的确认。这个解决方案已经实施了几个月,显然效果很好。但我还是想知道“心安”的官方说法。
[root@localhost ~]# ./test
Sample 1 first column = 1
Current value second column = 42
No more samples
All values at end:
1       84
2       100
[root@localhost ~]# ./test
Sample 1 first column = 1
Current value second column = 42
Sample 2 first column = 2
Current value second column = 100
No more samples
All values at end:
1       84
2       200