首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >带有gzstream库的rapidjson最后一个字符'-1‘

带有gzstream库的rapidjson最后一个字符'-1‘
EN

Stack Overflow用户
提问于 2014-11-22 11:37:55
回答 1查看 322关注 0票数 0

我编写了gzstream 1.5的简单包装器,用于与Rapidjson0.1 (ios,xcode 6.1)一起使用。

问题:我必须检查eof in Peek()并取()。否则,我得到'\377‘(-1)作为最后一个角色。我知道它是由eof的std::basic_stream::get()返回的。

什么是更优雅,适当和干净的解决方案?

代码语言:javascript
运行
复制
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_;
};
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-11-22 12:37:56

下面的答案是供对当前问题进行一般性讨论的。在那个时候,我没有查到rapidjson的行为。

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

实际上,您遇到的问题是,只要您不试图通过eof,输入流就会保持良好。GzInStream的接口不为用户提供任何可能,以检测EOF是否在Peek之前被击中或获取返回的无效值。这是由于C++ iostreams的设计:大多数情况下,低级别的API不会指示“流的结束”,除非您试图通过它,所以高级API不提供这个工具,因为在许多(非文件)情况下实现它并不简单。

标准C++ iostreams的peek()和get()函数返回int而不是char,原因是:它们被指定返回从流读取的字节为正数(8位字节的系统中为0.255),而错误时返回eof (-1)。您的Peek和Get函数无法返回256个不同的字节,EOF作为不同的返回值,因为257个可能性无法用char表示。因此,您的界面的客户端必须在从Peek或Take获得一个字符后询问"Good()“,以确定是否真的有一个字符需要获取。如果您的接口客户端这样做,那么无论您返回'\377‘还是'\0’还是任何其他值,都无关紧要,因为这个值无论如何都会被忽略。使用该“额外”字节的客户机是(在我的oppinion中) buggy,除非它被设计为忽略您返回的虚假NUL字节。

你可以用不同的方法来解决这个问题。

  • 如上文所示,修复客户端,并记录该类的行为。
  • 有好的()返回gs_->good() && !gs_->eof(),在超读eof之前依赖于gs_->eof()是真的
  • 从Peek返回int并进行提取,就像标准iostream所做的那样。
  • 返回一个boost::可选从Peek并采取,并返回boost::none如果遇到eof
  • 抛出一个异常表Peek和采取的情况下EOF。

大多数人会立即拒绝上一次建议的修复,因为它违反了“异常不应用于流控制”规则。我同意强迫客户端使用异常处理来检测EOF确实是不好的风格,但这实际上是不需要更改Peek的签名和接受或更改其他函数的语义的唯一可能性。我认为第二个建议(改变好的)是用例的方法。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27076948

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档