ここでは、スマート・ポイントと標準コンテナをシリアライズするための機能について説明します。
基本は単にシリアライズするだけです。特別な操作は必要ありませんが、コンテナについては2つ応用的な使い方があります。
- コンテナへ保存する要素をオブジェクト追跡する場合
- 保存先指定機能(保存先指定について )により分割保存したコンテナのデータを合成する場合
1.スマート・ポインタのシリアライズ方法
Theolizerはスマート・ポインタが管理するポインタをオーナー指定ポインタとしてシリアライズします。シリアライズする手順は通常のクラスと同じですが、少し注意事項があります。
スマート・ポインタをシリアライズするために、theolizer/memory.hをインクルードして下さい。
- unique_ptr
unique_ptrは通常通りシリアライズ可能です。
なお、std::unique_ptr<T[]>
はサポートしていません。T[]をシリアライズするためには、その要素数が必要ですが管理されていないため、対応できないのです。
- shared_ptr
同じインスタンスを管理するshared_ptrを保存し回復すると、その状況を回復します。
なお、同じインスタンスを管理するshared_ptrは同じオジェクト追跡単位内でシリアライズするようにして下さい。ポリモーフィズムにより回復処理中にポインタが置き換わった場合、シリアライズされていなかったshared_ptrとの共有状態が解除されます。
- weak_ptr
バインドしているshared_ptrをシリアライズします。ですので、shared_ptrと同様同じインスタンスを管理するものは同じオブジェクト追跡単位内でシリアライズして下さい。
スマート・ポインタの保存と回復処理(source/reference_and_test/basic2/test_support_stl.cpp)
unique_ptr、shared_ptr、weak_ptrの保存/回復のサンプル・ソースです。
{
std::unique_ptr<int> aUnique{new int{100}};
std::shared_ptr<int> aShared0{new int{200}};
std::shared_ptr<int> aShared1{aShared0};
std::shared_ptr<int> aSharedForWeak{new int{300}};
std::weak_ptr<int> aWeak{aSharedForWeak};
std::ofstream aStream("tutorise_support_stl.json");
aSerializer.clearTracking();
}
{
std::unique_ptr<int> aUnique{};
std::shared_ptr<int> aShared0{};
std::shared_ptr<int> aShared1{};
std::shared_ptr<int> aSharedForWeak{};
std::weak_ptr<int> aWeak{};
std::ifstream aStream("tutorise_support_stl.json");
aSerializer.clearTracking();
}
2.標準コンテナのシリアライズ方法
Theolizerは各種標準コンテナのシリアライズにも対応しています。
- それぞれ対応するインクルードが必要です。
- 一部の標準コンテナについて
保存先指定による合成回復、および、各要素を被ポインタとすること(他のシリアライズ対象のポインタから指す)に対応しています。
下記にその対応表を示します。
特記事項が幾つかあります。
- キー無しコンテナは先頭から順番にデータを回復します。
arrayはコンテナを拡張できないので、余分なシリアライス・データは破棄されます。
それ以外のキー無しコンテナ(vector, deque, forward_list, list)はシリアライズ・データの方が多い場合、コンテナを拡張して回復します。
両者ともシリアライズ・データの方が少ない場合、コンテナの余分な要素はそのまま保持されます。
- mapとunordered_mapは合成回復に対応しています。
これらはキー基準で回復しますので、保存先指定機能で分割したファイルを別々に編集した場合でも、同じキーのデータを同じインスタンスへ合成回復できます。
- setとunordered_setについて
これらは回復する際、シリアライズ・データを新規にコンストラクトしたインスタンスへ回復してからコンテナへ追加します。ですので、対応するシリアライズ・データがあった要素は単純回復(非合成回復)します。対応するシリアライズ・データがなかったコンテナの要素はそのまま維持されます。
- キーの重複を許すコンテナについて
multiset, multimap, unordered_multiset, unordered_multimapは、回復する際、一旦コンテナをクリアしてから、シリアライズ・データを回復します。これはキーの重複を許すため、シリアライズ・データと対応するコンテナの要素を特定できないためです。
2-1.標準コンテナを通常の使い方で保存/回復するサンプル・ソース
サンプル・ソース(source/reference_and_test/basic2/test_support_stl.cpp)
{
std::list<int> aList;
aList.emplace_back(100);
aList.emplace_back(200);
aList.emplace_back(300);
std::ofstream aStream("tutorise_support_stl_0.json");
}
{
std::list<int> aList;
std::ifstream aStream("tutorise_support_stl_0.json");
auto itr=aList.begin();
}
2-2.標準コンテナの要素を被ポインタとする保存/回復するサンプル・ソース
サンプル・ソース(source/reference_and_test/basic2/test_support_stl.cpp)
{
theolizer::VectorPointee<int> aVectorPointee;
aVectorPointee.emplace_back(400);
aVectorPointee.emplace_back(500);
aVectorPointee.emplace_back(600);
auto itr=aVectorPointee.begin();
int* aPtr0=&*itr++;
int* aPtr1=&*itr++;
int* aPtr2=&*itr++;
std::ofstream aStream("tutorise_support_stl_1.json");
aSerializer.clearTracking();
}
{
theolizer::VectorPointee<int> aVectorPointee;
int* aPtr0=nullptr;
int* aPtr1=nullptr;
int* aPtr2=nullptr;
std::ifstream aStream("tutorise_support_stl_1.json");
auto itr=aVectorPointee.begin();
aSerializer.clearTracking();
}
2-3.標準コンテナの要素を合成回復サンプル・ソース
サンプル・ソースsource/reference_and_test/basic2/test_support_stl.cpp)
{
std::map<std::string, StlTutorial> aMap;
aMap.emplace("first", StlTutorial(100, 200));
aMap.emplace("second", StlTutorial(101, 201));
aMap.emplace("third", StlTutorial(102, 202));
std::ofstream aStreamA("tutorise_support_stl_a.json");
std::ofstream aStreamB("tutorise_support_stl_b.json");
aSerializerA.clearTracking();
aSerializerB.clearTracking();
}
{
std::map<std::string, StlTutorial> aMap;
std::ifstream aStreamA("tutorise_support_stl_a.json");
std::ifstream aStreamB("tutorise_support_stl_b.json");
auto itr=aMap.find("first");
itr=aMap.find("second");
itr=aMap.find("third");
itr=aMap.find("first");
itr=aMap.find("second");
itr=aMap.find("third");
aSerializerA.clearTracking();
aSerializerB.clearTracking();
}
3.網羅的な使用例(自動テスト)の説明
スマート・ポインタと標準コンテナのサポートについて、全てのシリアライザ、全ての書式でテストしています。 また、保存先指定で分割保存後、合成回復のテストも同様に全てのシリアライザ、全ての書式でテストしています。
3-1.スマート・ポインタ
3-1-1.通常
unique_ptrとweak_ptrについては、使い方説明にて保存/回復テストしています。
オーナー指定ポインタを回復する時、例えばある派生クラスAのインスタンスを指しているポインタへ異なる派生クラスBを回復する場合があります。その時、元の派生クラスAのインスタンスは解放し、派生クラスBのインスタンスをコンストラクトして回復します。 しかし、shared_ptrは他のshared_ptrとポイント先を共有しているため元のインスタンスを解放できません。そのための対策を実装していいます。(shared_ptr回復中フラグを設け、元のインスタンスはshared_ptr処理側で管理しています。) その機能のテストのため、回復先のポインタが下記の3種類についてテストします。
- nullptrの時
- 回復するものと同じインスタンスを指している時
- 回復するものと異なるインスタンスを指している時
この時のシリアライズ対象クラスはSmartBaseとそれを派生したSmartDerivedです。
そして、それぞれについて、手動(トップ・レベル)、自動、手動(非トップ・レベル)による保存/回復をテストしています。 そのための補助クラスとして、SmartTestAutoとSmartTestManualを使っています。
source/reference_and_test/basic2/test_support_stl.cppでテスト関数を定義してます。
- 保存処理
template<class tSerializer>
void saveSupportStl(tSerializer& iSerializer)の前半
- 回復処理
template<class tSerializer>
void loadSupportStl(tSerializer& iSerializer)の前半
3-1-2.合成回復
unique_ptrとshared_ptrについて、それが管理するクラスをDestAとDestBに分割して保存し合成回復できることを確認しています。 source/reference_and_test/basic2/test_support_stl.cppでテスト関数を定義してます。
- 保存処理
template<class tSerializer>
void saveSupportStlDestinations(tSerializer& iSerializer)の前半
- 回復処理
template<class tSerializer>
void saveSupportStlDestinations(tSerializer& iSerializer)の前半
3-2.標準コンテナのテスト
3-2-1.通常
サポートしている全てのコンテナについて、下記について正しく保存/回復できることをテストしています。
- 要素の型はint型とクラス(TestStl)
- 被ポインタをサポートしているコンテナについてはオブジェクト追跡
unorderedコンテナに対応するため、TestStlはstd::hashクラスを特殊化しています。
下記関数テンプレートを使っています。
対象コンテナ | 関数テンプレート |
array | saveContainerFixed, loadContainerFixed |
vector(bool以外), deque, list, forward_list | saveContainer, loadContainer |
set, multiset, unordered_set, unordered_multiset | saveContainerSet, loadContainerSet |
map, multimap, unordered_map, unordered_multimap | saveContainerMap, loadContainerMap |
source/reference_and_test/basic2/test_support_stl.cppでテスト関数を定義してます。
- 保存処理
template<class tSerializer>
void saveSupportStl(tSerializer& iSerializer)の後半
- 回復処理
template<class tSerializer>
void loadSupportStl(tSerializer& iSerializer)の後半
3-2-2.合成回復
合成回復をサポートしている全てのコンテナについて、下記について正しく保存/回復できることをテストしています。
- 要素の型はクラス(TestStlDestinations)
TestStlDestinationsは保存先としてDestAとDestBを指定したメンバを定義しています。
下記関数テンプレートを使っています。
対象コンテナ | 関数テンプレート |
array | saveFixed, loadFixed |
vector(bool以外), deque, list, forward_list | saveNoKey, loadNoKey |
map, unordered_map | saveKey, loadeKey |
source/reference_and_test/basic2/test_support_stl.cppでテスト関数を定義してます。
- 保存処理
template<class tSerializer>
void saveSupportStlDestinations(tSerializer& iSerializer)の後半
- 回復処理
template<class tSerializer>
void loadSupportStlDestinations(tSerializer& iSerializer)の後半