I have a binary packet format which I must implement a C++ reader for. The library uses Qt 4, and the packet source could be any QIODevice, for example, QTcpSocket, QFile or QBuffer. The format includes the packet format, and each packet may also have a lot of sub-structures inside. I need the reader to return the following:
- the packet header;
- the array of sub-structures;
- the error status of a read operation - success, an error, or not enough data (particularly when reading from a socket or another sort of buffering device).
There are various possible approaches to the reader API:
Packet read(Status &status);
- return by value, and return the error status through the reference argument.Packet *read(bool *ok);
- return NULL on error or if not enough data, write true or false to theok
variable (if not NULL) depending on that.Packet *read();
- return NULL on error or if not enough data, call another methodbool wasError();
to check what happened. This one could be merged with the previous one by making theok
parameter have the default value ofNULL
.Status read(Packet &packet);
- if the returned status isOk
, the read value is placed into thepacket
variable, otherwise it indicates either an error or EOF.Packet read();
- return by value, in case of EOF or error return a special "null packet" value. CallwasError()
to determine what happened.
There are other possible combinations, of course. There doesn't seem to be the best choice. The approaches 1, 2 and 4 require the caller to declare a separate variable to store the result. The approaches 2 and 3 involve messing with the heap, which I don't want to do for obvious reasons. The approach 1 doesn't make it clear what is returned in case of error. The approach 5 fixes that, but introduces a special "null" flag into the packet structure, although it probably doesn't belong there.
I could take the 5th approach, but return a special structure containing a packet and the status info, but that introduces another "synthetic" type and still leaves open the question "What will the packet field contain in case of an error?"
Or I could take the 3rd approach and return a QSharedPointer<Packet>
instead, so the caller doesn't have to mess with heap manually. But the Packet
structure will probably already be a kind of smart pointer (a shared class) for the sake of the Pimpl. Maybe I can use that internal pointer instead and introduce an isNull()
method, like QString does.
Is there a better, or traditional way of doing it?