我编写了gzstream 1.5的简单包装器,用于与Rapidjson0.1 (ios,xcode 6.1)一起使用。
问题:我必须检查eof in Peek()并取()。否则,我得到'\377‘(-1)作为最后一个角色。我知道它是由eof的std::basic_stream::get()返回的。
什么是更优雅,适当和干净的解决方案?
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_;
};
发布于 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()
是真的大多数人会立即拒绝上一次建议的修复,因为它违反了“异常不应用于流控制”规则。我同意强迫客户端使用异常处理来检测EOF确实是不好的风格,但这实际上是不需要更改Peek的签名和接受或更改其他函数的语义的唯一可能性。我认为第二个建议(改变好的)是用例的方法。
https://stackoverflow.com/questions/27076948
复制相似问题