2

我有一个简单的类,其中包含一个动态分配的数组,我需要对其进行序列化,以便将其存储在二进制文件中。由于数组的原因,我不能使用 sizeof(MyClass) 来简单地分配缓冲区。

该类如下所示:

class ReplayFrame
{
public:
    // ...

private:
    int dataType_;
    int timeStamp_;
    int frameNumber_;
    size_t dataSize_;
    char* data_;
};

这是我想出的一个解决方案:

std::ostream& operator<< (std::ostream& out, const ReplayFrame& frame)
{
    out.write((char *) &frame.dataType_, sizeof(int));
    out.write((char *) &frame.timeStamp_, sizeof(int));
    out.write((char *) &frame.frameNumber_, sizeof(int));
    out.write((char *) &frame.dataSize_, sizeof(size_t));
    out.write(frame.data_, frame.dataSize_);

    return out;
}

这对我来说似乎很好,但它在某种程度上改变了 << 运算符的含义。所以也许类似的东西std::ostream& ReplayFrame::serialize(std::ostream& out, const ReplayFrame& frame)会更好?

或者也许我应该有一个serialize()不使用流的方法,而是返回大小和指向序列化对象的指针,然后我自己编写,比如:

ReplayFrame replayFrame;
int size;

char *frameSerialized = replayFrame.serialize(size);
fileStream.write(frameSerialized, size);

delete frameSerialized; // or frameSerialized.release() ?

正如你所看到的,我很困惑,所以我愿意接受任何好的建议。(注意:我使用 Qt,没有 boost,也没有 c++11)。

4

1 回答 1

1

首先是重要的事情:只是将二进制数据转储到任何地方,无论是文件、另一个进程还是任何一个坏主意。您总是希望格式化数据,尽管格式可以是二进制的,并且它可能与您当前正在开发的系统的内部表示相匹配。但是,您应该意识到,任何勉强成功的程序都将比不同的编译器世代更长寿,可能是处理器升级,并被移植到另一个平台。如果您的二进制格式取决于编译器现在如何表示数据,那么所有这些都会令人头疼。如果该计划最终成功,那将是一个更大的麻烦。

您要注意的二进制格式的方面是

  • 单个单词的大小
  • 字内字节的排序
  • 单词之间的潜在填充
  • 写入数据项的顺序

例如,仅使用sizeof()来确定转储或读取的字节数在 32 位和 64 位平台之间不起作用。仅仅按照它们来的顺序转储字节是行不通的,例如,在 PowerPC 和 x86 系统之间。现在只是转储字节可能很容易,但在中期它会产生更多问题。

重载输出操作符是可以的,只要你使用这个操作符的文本格式流类!您可以使用std::streambuf与读取和写入字节有关的层,例如,std::filebuf读取或写入文件,但是对于二进制格式的流,您希望在重载时使用专用的二进制流系统operator<<()。当然,这意味着类需要重载相应的操作才能在这个序列化系统中工作,但是混合文本和二进制格式的想法几乎肯定会引起很多麻烦。

于 2012-11-18T22:20:59.460 回答