包读取器Qt / C ++ API设计

时间:2012-07-10 08:16:05

标签: c++ api qt

我有一个二进制数据包格式,我必须为它实现一个C ++阅读器。该库使用Qt 4,数据包源可以是任何QIODevice,例如QTcpSocket,QFile或QBuffer。格式包括数据包格式,每个数据包内部也可能有很多子结构。我需要读者返回以下内容:

  • 包头;
  • 子结构数组;
  • 读取操作的错误状态 - 成功,错误或数据不足(特别是从套接字或其他类型的缓冲设备读取时)。

读者API有各种可能的方法:

  1. Packet read(Status &status); - 按值返回,并通过引用参数返回错误状态。
  2. Packet *read(bool *ok); - 错误时返回NULL,或者如果数据不够,则对ok变量(如果不是NULL)写入true或false,具体取决于此。
  3. Packet *read(); - 错误时返回NULL或者如果数据不够,请调用另一个方法bool wasError();来检查发生了什么。通过使ok参数的默认值为NULL,可以将此方法与前一个方法合并。
  4. Status read(Packet &packet); - 如果返回的状态为Ok,则将读取的值放入packet变量中,否则表示错误或EOF。
  5. Packet read(); - 按值返回,如果是EOF或错误,则返回一个特殊的"空数据包"值。致电wasError()以确定发生了什么。
  6. 当然还有其他可能的组合。似乎并不是最好的选择。方法1,2和4要求调用者声明一个单独的变量来存储结果。方法2和方法3涉及到堆乱,我不想出于显而易见的原因。方法1没有明确错误情况下返回的内容。方法5修复了这个问题,但引入了一个特殊的" null"标记到数据包结构中,虽然它可能不属于那里。

    我可以采用第5种方法,但返回一个包含数据包和状态信息的特殊结构,但这会引入另一个"合成"输入并仍然打开问题"如果出现错误,数据包字段包含什么?"

    或者我可以采用第3种方法并返回QSharedPointer<Packet>,这样调用者就不必手动弄乱堆。但是为了Pimpl,Packet结构可能已经是一种智能指针(共享类)。也许我可以使用那个内部指针,并引入一个isNull()方法,就像QString那样。

    是否有更好或传统的做法?

1 个答案:

答案 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()方法来检索错误状态。

这个实现允许我:

  1. 创建优雅的循环,例如while (!(packet = reader->readPacket()).isNull()) ...
  2. 避免出现像&#34;错误&#34;等不相关的字段。或&#34; null&#34;在Packet类中。
  3. 避免手动分配或删除指针,或者不得不在呼叫者旁边明确地弄乱智能指针。
  4. 使用默认构造函数时避免使用未初始化的字段。
  5. 它还远未完美,因为有必要提供error参数或稍后调用wasError()。但我认为强制呼叫者检查错误的唯一方法是使用例外,但我不想出于便携的原因这样做。