編集:実際の問題に対処するために、以下に新しい回答が追加されました。
あなたの質問は、同じオブジェクトに繰り返し逆シリアル化することを意味します。それがきれいかどうかは状況次第です。たとえば、チェス盤を持っている場合、(最後に保存したゲームから続行するために) 駒の初期位置を同期する必要があります。ゲームのプレイ中に移動を通信するには、変更されたもののみを転送するボード オブジェクト全体を送信するのではなく、個々の移動を個別のオブジェクトとして送信することをお勧めします (受信すると、ボード オブジェクトに適用されます)。すでに「初期化」されている場合。そうすれば、最初に入力を検証し、無効な動きを無視できます。とにかく、私はそれについて言及したかっただけです。次に進みましょう。
複数回同期される可能性のあるオブジェクトがあり、メンバー データが 1 回だけ転送される必要がある場合は、オブジェクトが「初期化」されているかどうかを決定します (したがって、すべてを送信する必要があるか、サブセットのみを送信する必要があるかどうか)。フラグを使用する (シリアル化されていない)。
次に、投稿したコードと同じように、オブジェクトのシリアル化コードでフラグを確認できます(ただし、フラグはシリアル化メソッドのパラメーターではなく、デ/シリアル化するオブジェクトのメンバー変数です)。フラグが設定されている場合は、すべてを逆シリアル化し、フラグをリセットします。クライアントとサーバーの両方でフラグの状態が同じである必要があります。そうしないと、シリアライゼーションが中断されます。
または、最初にフラグをシリアライズして、デシリアライゼーションを実行する必要がある方法をレシーバーに伝えることもできます (たとえば、メンバー データ グループごとに 1 ビット)。
逆シリアル化はシリアル化と一致する必要があることに注意してください。シリアル化されたのと同じ順序で、同じオブジェクトを抽出する必要があります。
ただし、逆シリアル化されるのと同じレベルのクラス階層でシリアル化されている場合は、ポリモーフィック クラスをシリアル化できます (疑わしい場合は、送信時にベース ポインターにキャストし、ベース ポインターを介して逆シリアル化します)。
2 番目の質問に関して、探しているのは非侵入型のシリアライゼーションです。非侵入型のシリアライゼーションでは、独立した関数を呼び出し、シリアライズするオブジェクトをパラメーターとして渡します (これが std::vector と boost::shared_ptr のシリアライズ方法です)。を使用BOOST_SERIALIZATION_SPLIT_FREE
して、自立serialize()
関数をsave()
とに分割できますload()
。侵入シリアライゼーションの場合はBOOST_SERIALIZATION_SPLIT_MEMBER
.
一般化された逆シリアル化関数 (たとえば、ネットワークを介してオブジェクトを送信する関数) を作成するには、テンプレートを使用できます。
template<typename T>
void transmit( const T& data ) {
// ...
archive << data
socket << archive_stream;
}
このメソッドの制限は、受信者が送信されたオブジェクトの種類を認識している必要があることです。ランダム オブジェクトを送信する場合は、それらをポリモーフィックにします。
IData* data = 0;
archive >> data;
switch( data->type() ) {
case TYPE_INIT:
return dispatch( static_cast<Board*>(data) );
case TYPE_MOVE:
return dispatch( static_cast<Move*>(data) );
case TYPE_CHAT:
return dispatch( static_cast<ChatMsg*>(data) );
}
UPDATE : (カスタム) シリアライゼーション メソッド/関数の動作を制御する必要がある場合は、シリアライズされる型に不明な状態に基づいて、状態を保持する独自のアーカイブ クラスを実装できます。その後、シリアライゼーション関数は状態を照会し、それに応じて動作できます。
データを逆シリアル化する方法を示すために、この状態 (または適切な置換) もシリアル化する必要があります。たとえば、シリアル化関数のこの「異なる動作」はある種の圧縮である可能性があり、状態は使用される圧縮の種類です。
カスタム出力アーカイブの最小限の例を次に示します。詳細については、既存のアーカイブからの派生を読んで、ブースト ソースを掘り下げることができます。
変更できないクラスがあるとします。
struct Foo {
Foo() : i(42), s("foo") {}
int i;
std::string s;
};
シリアライズしたい、i
および/またはs
クラスに不明な条件に基づいています。ラッパーを作成してシリアル化して状態を追加することもできますが、オブジェクトがベクター (またはその他のクラス) 内にある場合、これは機能しません。
代わりに、アーカイブに状態を認識させる方が簡単な場合があります。
#include <boost/archive/text_oarchive.hpp>
// using struct to omit a bunch of friend declarations
struct oarchive : boost::archive::text_oarchive_impl<oarchive>
{
oarchive(std::ostream& os, unsigned flags=0)
: boost::archive::text_oarchive_impl<oarchive>(os,flags),mask(0){}
// forward to base class
template<class T> void save( T& t ) {
boost::archive::text_oarchive_impl<oarchive>::save(t);
}
// this is the 'state' that can be set on the archive
// and queried by the serialization functions
unsigned get_mask() const { return mask; }
void set_mask(unsigned m) { mask = m; }
void clear_mask() { mask = 0; }
private:
unsigned mask;
};
// explicit instantiation of class templates involved
namespace boost { namespace archive {
template class basic_text_oarchive<oarchive>;
template class text_oarchive_impl<oarchive>;
template class detail::archive_serializer_map<oarchive>;
} }
// template implementations (should go to the .cpp)
#include <boost/archive/impl/basic_text_oarchive.ipp>
#include <boost/archive/impl/text_oarchive_impl.ipp>
#include <boost/archive/impl/archive_serializer_map.ipp>
設定してクエリする状態は次のとおりです。
enum state { FULL=0x10, PARTIAL=0x20 };
状態を設定するメソッド (これは非常に基本的な例です):
oarchive& operator<<(oarchive& ar, state mask) {
ar.set_mask(ar.get_mask()|mask);
return ar;
}
最後に、(非侵入型) シリアライゼーション関数:
namespace boost { namespace serialization {
template<class Archive>
void save(Archive & ar, const Foo& foo, const unsigned int version)
{
int mask = ar.get_mask(); // get state from the archive
ar << mask; // serialize the state! when deserializing,
// read the state first and extract the data accordingly
if( mask & FULL )
ar << foo.s; // only serialize s if FULL is set
ar << foo.i; // otherwise serialize i only
ar.clear_mask(); // reset the state
}
} } // boost::serialization
BOOST_SERIALIZATION_SPLIT_FREE(Foo)
そして、これは次のように使用できます。
int main() {
std::stringstream strm;
oarchive ar(strm);
Foo f;
ar << PARTIAL << f << FULL << f;
std::cout << strm.str();
}
この例の目的は、原理を説明することだけです。実動コードには基本的すぎます。