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,我将它转换为uint64
。 Before Fail
和 Bad 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 上失败的主要内容,如果未能解决你的问题,请参考以下文章
boost::interprocess::file_lock 与 std::ostream 一起使用时的错误行为
C++ 网络程序设计:Boost Asio、序列化和 OStream
命名空间中的ostream operator <<隐藏其他ostream :: operator [duplicate]