シリアル化ライブラリを使用しない場合は、各クラスにシリアル化サポートを追加することをお勧めします。
struct My_Struct
{
std::string my_string;
unsigned int my_int;
void Load_From_Buffer(unsigned char const *& p_buffer)
{
my_string = std::string(p_buffer);
p_buffer += my_string.length() + 1; // +1 to account for the terminating nul character.
my_int = *((unsigned int *) p_buffer);
p_buffer += sizeof(my_int);
}
};
unsigned char * const buffer = ReadFile(filename);
unsigned char * p_buffer = buffer;
My_Struct my_variable;
my_variable.Load_From_Buffer(p_buffer);
その他の便利なインターフェースメソッド:
unsigned int Size_On_Stream(void) const; // Returns the size the object would occupy in the stream.
void Store_To_Buffer(unsigned char *& p_buffer); // Stores object to buffer, increments pointer.
テンプレートを使用すると、シリアル化機能を拡張できます。
void Load_From_Buffer(std::string& s, unsigned char *& p_buffer)
{
s = std::string((char *)p_buffer);
p_buffer += s.length() + 1;
}
void template<classtype T> Load_From_Buffer(T& object, unsigned char *& p_buffer)
{
object.Load_From_Buffer(p_buffer);
}
編集1:構造を直接記述しない理由
CおよびC++では、構造体のサイズはそのメンバーのサイズの合計と等しくない場合があります。
コンパイラーは、メンバーがアドレス上に整列されるように、メンバー間に パディングまたは未使用のスペースを挿入できます。
たとえば、32ビットプロセッサは4バイト境界で物事をフェッチするのが好きです。構造体に1つchar
あり、その後にが続く場合int
、on相対アドレス1が作成さint
れます。これは、4の倍数ではありません。コンパイラーは、相対アドレス4に並ぶように構造体をパディングint
します。
構造体には、ポインターまたはポインターを含むアイテムが含まれる場合があります。
たとえばstd::string
、文字列に3文字または300文字が含まれていても、タイプのサイズは40である場合があります。これには、実際のデータへのポインタがあります。
エンディアン。
マルチバイト整数では、最上位バイト(MSB)、別名ビッグエンディアン(人間が数値を読み取る方法)または最下位バイト(別名リトルエンディアン)などの一部のプロセッサが最初に使用されます。リトルエンディアン形式は、ビッグエンディアンよりも読み取りに必要な回路が少なくて済みます。
編集2:バリアントレコード
配列やコンテナなどを出力する場合は、コンテナ全体(未使用のスロットを含む)を出力するか、コンテナ内のアイテムのみを出力するかを決定する必要があります。コンテナ内のアイテムのみを出力するには、バリアントレコード手法を使用します。
バリアントレコードを出力するための2つの手法:数量の後にアイテムが続くか、アイテムの後に番兵が続く。後者は、センチネルがヌル文字であるCスタイルの文字列の記述方法です。
もう1つの手法は、アイテムの数量を出力し、その後にアイテムを出力することです。したがって、0、1、2、3、4、5の6つの数値がある場合、出力は次のようになります
。6//アイテムの
数
01
2
3
4
5
上記のLoad_From_Bufferメソッドでは、数量を保持するための一時的なものを作成し、それを書き出してから、コンテナーの各アイテムを追跡します。