Ostream tellp 在 Windows 上失败,但在 Linux 上失败

Posted

技术标签:

【中文标题】Ostream tellp 在 Windows 上失败,但在 Linux 上失败【英文标题】:Ostream tellp fails on Windows but not on Linux 【发布时间】:2016-12-06 01:33:31 【问题描述】:

我在 Windows 10 和带有 Qt 5.7 的 Linux 中执行相同的代码,它只在 Linux 中有效。 我正在尝试确定我刚刚创建的 Ostream iostream 的大小,因此它应该为空。在 Linux Size() 中返回 0,但在 Windows 中它返回 -1,因为 tellp() 失败。

    #include "stdafx.h"
    #include <iostream>
    #include <fstream>
    #include <memory>
    #include <sstream>

    class Foo 
private:
    std::shared_ptr<std::ostream> myOstream;
    std::shared_ptr<std::istream> myIstream;

public:
    Foo::Foo(std::shared_ptr<std::iostream> myIostream)
        : myIstream(std::static_pointer_cast<std::istream>(myIostream))
        , myOstream(std::static_pointer_cast<std::ostream>(myIostream))
    

    uint64_t Foo::Size() 
        int ret = 0;

        std::cout << "Before – Fail Flag: " << myOstream->fail() << ", Bad Bit: " << myOstream->bad() << std::endl;

        if (myIstream.get() != nullptr) 
            myIstream->clear();
            auto oldPos = myIstream->tellg();            //returns 0
            myIstream->seekg(0, std::ios_base::end);
            ret = static_cast<int>(myIstream->tellg());  //returns 0
            myIstream->seekg(oldPos);
        

        if (myOstream.get() != nullptr) 
            auto oldPos = myOstream->tellp();           //returns -1
            myOstream->seekp(0, std::ios_base::end);
            ret = static_cast<int>(myOstream->tellp()); //returns -1
            myOstream->seekp(oldPos);
        
            //Fail Flag returns -1, Bad Bit Flag returns 0
        std::cout << "After – Fail Flag: " << myOstream->fail() << ", Bad Bit: " << myOstream->bad() << std::endl;

        return static_cast<uint64_t>(ret);
    
;

int main()

    auto myStringStream = std::make_shared<std::stringstream>(
        std::ios::in | std::ios::out | std::ios::binary);

    Foo foo(std::static_pointer_cast<std::iostream>(myStringStream));

    std::cout << "Size: " << foo.Size() << std::endl;

    system("pause");
    return 0;

我得到18446744073709551615 作为大小,因为它返回-1,我将它转换为uint64Before FailBad flag 都返回 0。After Fail 标志返回 1,Bad flag 返回 0。

我读到是因为哨兵的建造失败了,但我不知道如何修复它。


编辑:

在玩了一些代码之后,我意识到我遗漏了部分代码。我的理解是,要获得大小,代码会计算出已经读取了多少,将指针调整到该位置,然后计算还剩下多少并返回该值。但是由于 iostream 是新的并且它是强制转换的,所以 .get() 返回内存位置并传递了 if 语句。然后 istream 部分将指针更改到最后,这就是 ostream 部分失败的原因。这是正确的吗?

编辑 2: 找到了解决方案。问题出在 myIstream->seekg(oldPos) 但由于状态在 myIstream 和 myOstream 之间共享,因此直到 ostream 调用才捕获到错误。字符串缓冲区是延迟分配的,但 seekp() 不适应这一点。解决这个问题的方法是用垃圾数据填充字符串流,或者在使用它之前检查它是否为空。

【问题讨论】:

如果fail() 为真,tellp() 返回 -1。很明显seekp() 之前失败了。但是您没有进行任何错误处理。例如,ostream 在您尝试查找之前是否打开了输出文件/缓冲区? iostream 运行在什么样的缓冲区上? “我刚刚创建但尚未初始化的 Iostream”是什么意思?您是否创建 iostream 或其一些派生类(fstream、stringstream)?你怎么不初始化它?显示问题的完整代码会有所帮助。 抱歉,我遗漏了部分代码。 iostream 被解析为一个 istream 和一个 ostream,它操纵两个流上的指针来确定大小。如果没有 istream,代码就可以工作,所以我猜 istream 部分会将指针更改到最后,这就是 ostream 部分失败的原因。这是正确的吗? 欢迎来到 Stack Overflow!此处鼓励自我回答,但我们要求将其作为实际答案发布,而不是作为对您问题的编辑。谢谢。 【参考方案1】:

找到了解决办法。问题出在 myIstream->seekg(oldPos) 但由于状态在 myIstream 和 myOstream 之间共享,因此直到 ostream 调用才捕获到错误。字符串缓冲区是延迟分配的,但 seekp() 不适应这一点。解决这个问题的方法是用垃圾数据填充字符串流,或者在使用它之前检查它是否为空。 – Namox9001

【讨论】:

以上是关于Ostream tellp 在 Windows 上失败,但在 Linux 上失败的主要内容,如果未能解决你的问题,请参考以下文章

Nanopb 从 pb_ostream_t 获取字符串

boost::interprocess::file_lock 与 std::ostream 一起使用时的错误行为

C++学习笔记C++输入输出流

C++ 网络程序设计:Boost Asio、序列化和 OStream

命名空间中的ostream operator <<隐藏其他ostream :: operator [duplicate]

使用 * 分配给 ostream_iterators