gpt4 book ai didi

c++ - 带有 gzstream 库的 rapidjson 最后一个字符 '-1'

转载 作者:行者123 更新时间:2023-11-28 06:33:55 36 4
gpt4 key购买 nike

我编写了 gzstream 1.5 的简单包装器,用于 rapidjson 0.1(ios、xcode 6.1)。

问题:我必须在 Peek() 和 Take() 中检查 eof。否则,我得到 '\377' (-1) 作为最后一个字符。我知道它由 std::basic_stream::get() 在 eof 处返回。

什么是更优雅、正确和干净的解决方案?

class GzOutStream {
public:
GzOutStream(std::string filename) : gs_(new ogzstream(filename.c_str())) {}
bool Good() { return gs_->good(); }
void Close() { delete gs_; gs_ = nullptr; }
size_t Tell() { return gs_->tellp(); }
void Put(char c) { gs_->put(c); }

// Not implemented
char* PutBegin() { return 0; }
size_t PutEnd(char*) { return 0; }

private:
ogzstream* gs_;
};

class GzInStream {
public:
GzInStream(std::string filename) : gs_(new igzstream(filename.c_str())) {}
bool Good() { return gs_->good(); }
void Close() { delete gs_; gs_ = nullptr; }
char Peek() { return gs_->eof()? '\0' : gs_->peek(); }
char Take() { return gs_->eof()? '\0' : gs_->get(); }
size_t Tell() { return gs_->tellg(); }
void Put(char c) { } // Stab

// Not implemented
char* PutBegin() { return 0; }
size_t PutEnd(char*) { return 0; }

private:
igzstream* gs_;
};

最佳答案

下面的答案是为手头问题的一般性讨论而提供的。那时我没有查看 rapidjson 的行为。

您的类旨在成为 gzip 输入流和 rapidjson 之间的胶合逻辑,因此您必须实现 rapidjson 所需的接口(interface)。它甚至没有良好的功能。 rapidjson 期望的接口(interface)在 EOF 上返回 '\0',因此这是您必须做的唯一选择。如果您使用的 gzip 流类正在实现 C++ 流模型,您可以使用 https://github.com/miloyip/rapidjson/blob/master/doc/stream.md 中描述的模式。在“示例 istream 包装器”部分中,它以通常与 C++ iostreams 一起使用的方式进行 EOF 检测。如果您当前的方式适用于 gz 流,您也可以保持原样。


只要您不尝试过去 eof,您实质上就是遇到了输入流保持良好状态的问题。 GzInStream 的接口(interface)不向用户提供任何可能性来检测在 Peek 或 Take 返回无效值之前是否已命中 EOF。这是由于 C++ iostreams 的设计:大多数情况下,低级 API 不会指示“流结束”,除非您尝试越过它,因此高级 API 不提供此功能,因为它很重要在许多(非文件)情况下实现。

标准 C++ iostream 的 peek() 和 get() 函数返回 int 而不是 char 的原因是:它们被指定返回从流中读取的字节作为正数(在具有 8 位字节的系统上为 0..255),同时在出错时返回 eof (-1)。您的 Peek 和 Get 函数无法返回 256 个不同的字节和 EOF 作为不同的返回值,因为 257 种可能性无法用 char 表示。因此,就目前而言,您界面的客户端必须在从 Peek 或 Take 获取字符后询问“Good()”,以查明是否真的有要获取的字符。如果您的接口(interface)的客户端这样做,则无论您返回 '\377' 或 '\0' 还是任何其他值都没有关系,因为该值无论如何都会被忽略。使用该“额外”字节的客户端(在我看来)是错误的,除非它被设计为忽略您返回的虚假 NUL 字节。

你可以用不同的方式解决这个问题

  • 如上所示修复您的客户端,并记录该类的行为。
  • 让 Good() 返回 gs_->good() && !gs_->eof(),在重读 eof 之前依赖于 gs_->eof() 为真
  • 从 Peek and Take 返回一个整数,就像标准的 iostream 一样。
  • 从 Peek 和 Take 返回一个 boost::optional,如果遇到 eof 则返回 boost::none
  • 在 EOF 的情况下从 Peek 和 Take 中抛出异常。

大多数人会立即拒绝最后提议的修复,因为它违反了“异常不应该用于流量控制”的规则。我同意强制客户端使用异常处理来检测 EOF 确实是一种糟糕的风格,但实际上这是唯一一种既不需要更改 Peek 和 Take 的签名也不需要更改其他函数语义的可能性。我希望第二个建议(改变好)是你用例的方式。

关于c++ - 带有 gzstream 库的 rapidjson 最后一个字符 '-1',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27076948/

36 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com