我有一个二进制数据包格式,我必须为它实现一个C ++阅读器。该库使用Qt 4,数据包源可以是任何QIODevice,例如QTcpSocket,QFile或QBuffer。格式包括数据包格式,每个数据包内部也可能有很多子结构。我需要读者返回以下内容:
读者API有各种可能的方法:
Packet read(Status &status);
- 按值返回,并通过引用参数返回错误状态。Packet *read(bool *ok);
- 错误时返回NULL,或者如果数据不够,则对ok
变量(如果不是NULL)写入true或false,具体取决于此。Packet *read();
- 错误时返回NULL或者如果数据不够,请调用另一个方法bool wasError();
来检查发生了什么。通过使ok
参数的默认值为NULL
,可以将此方法与前一个方法合并。Status read(Packet &packet);
- 如果返回的状态为Ok
,则将读取的值放入packet
变量中,否则表示错误或EOF。Packet read();
- 按值返回,如果是EOF或错误,则返回一个特殊的"空数据包"值。致电wasError()
以确定发生了什么。当然还有其他可能的组合。似乎并不是最好的选择。方法1,2和4要求调用者声明一个单独的变量来存储结果。方法2和方法3涉及到堆乱,我不想出于显而易见的原因。方法1没有明确错误情况下返回的内容。方法5修复了这个问题,但引入了一个特殊的" null"标记到数据包结构中,虽然它可能不属于那里。
我可以采用第5种方法,但返回一个包含数据包和状态信息的特殊结构,但这会引入另一个"合成"输入并仍然打开问题"如果出现错误,数据包字段包含什么?"
或者我可以采用第3种方法并返回QSharedPointer<Packet>
,这样调用者就不必手动弄乱堆。但是为了Pimpl,Packet
结构可能已经是一种智能指针(共享类)。也许我可以使用那个内部指针,并引入一个isNull()
方法,就像QString那样。
是否有更好或传统的做法?
答案 0 :(得分:0)
嗯,我已经按照以下方式实施了它。
阅读方法的签名是:
Packet readPacket(bool *error = NULL);
Packet类看起来像这样:
class Packet {
inline Packet(): p(NULL) {} // this is returned on error or EOF
Packet(const Header &header, const Data &data);
inline bool isNull() {return p == NULL;}
private:
QSharedDataPointer<PacketPrivate> p;
};
如果bool wasError()
参数未提供给error
函数,数据包阅读器还会使用readPacket()
方法来检索错误状态。
这个实现允许我:
while (!(packet = reader->readPacket()).isNull()) ...
它还远未完美,因为有必要提供error
参数或稍后调用wasError()
。但我认为强制呼叫者检查错误的唯一方法是使用例外,但我不想出于便携的原因这样做。