Theolizer
Version.1.2.0
serializer for C++ / Do you want to update your classes easily ?
7c.object_tracking.h
[詳解]
1
//############################################################################
2
/*!
3
@brief ドキュメント・ファイル-使用方法(個別)
4
@ingroup Documents
5
@file 7c.object_tracking.h
6
@author Yoshinori Tahara
7
@date 2017/01/06 Created
8
*/
9
/*
10
© 2016 Theoride Technology (http://theolizer.com/) All Rights Reserved.
11
"Theolizer" is a registered trademark of Theoride Technology.
12
13
"Theolizer" License
14
In the case where you are in possession of a valid “Theolizer” License,
15
you may use this file in accordance with the terms and conditions of
16
the use license determined by Theoride Technology.
17
18
General Public License Version 3 ("GPLv3")
19
You may use this file in accordance with the terms and conditions of
20
GPLv3 published by Free Software Foundation.
21
Please confirm the contents of GPLv3 at https://www.gnu.org/licenses/gpl.txt .
22
A copy of GPLv3 is also saved in a LICENSE.TXT file.
23
24
商用ライセンス
25
あなたが有効なTheolizer商用ライセンスを保持している場合、
26
セオライド テクノロジーの定める使用許諾書の条件に従って、
27
このファイルを取り扱うことができます。
28
29
General Public License Version 3(以下GPLv3)
30
Free Software Foundationが公表するGPLv3の使用条件に従って、
31
あなたはこのファイルを取り扱うことができます。
32
GPLv3の内容を https://www.gnu.org/licenses/gpl.txt にて確認して下さい。
33
またGPLv3のコピーをLICENSE.TXTファイルにおいてます。
34
*/
35
//############################################################################
36
37
/*!
38
@page ObjectTracking オブジェクト追跡について
39
ここでは、オブジェクト追跡について説明します。
40
41
<br>
42
//############################################################################
43
@section HowToObjectTracking 1.オブジェクト追跡の使い方
44
//############################################################################
45
46
<br>
47
@subsection HowToObjectTracking11 1-1.指定方法
48
<b>・ポインタ型の指定(通常通りのシリアライズ指定です)</b>
49
50
1. メンバ変数の場合は、通常通り保存指定<br>
51
2. THEOLIZER_PROCESS()マクロ<br>
52
53
<b>・オーナー・ポインタ型の指定(オーナー指定)</b>
54
55
1. メンバ変数の場合は、THEOLIZER_ANNOTATE(FS:...<...>Owner)<br>
56
このアノテーションはポインタに対してのみ指定できます。<br>
57
2. THEOLIZER_PROCESS_OWNER()マクロ<br>
58
このマクロはボインタのみ指定できます。<br>
59
60
また、回復時は初期値が必要です。nullptr、もしくは、適正なインスタンスへのポインタを設定して下さい。ポイント先インスタンスのクラスとシリアライズ・データ内のクラスが同じならば設定されていたインスタンスを維持したまま回復します。(これは保存先指定機能により複数のファイルに別々に保存されたメンバを統合するための機能です。) もし、クラスが異なる場合は解放し、シリアライズ・データと同じクラスをnewして回復します。nullptrの時も同様です。
61
62
<b>・オブジェクト追跡指定</b>
63
64
1. メンバ変数の場合は、THEOLIZER_ANNOTATE(FS:...<...>Pointee)
65
2. THEOLIZER_PROCESS_POINTEE()マクロ
66
67
@subsection HowToObjectTracking12 1-2.サンプル・ソース
68
69
<b>サンプル用のクラス定義:(source/reference_and_test/basic2/test_object_tracking.h)</b><br>
70
(静的定義領域、動的生成領域については@ref HowToObjectTracking33 を参照下さい。)
71
72
@dontinclude basic2/test_object_tracking.h
73
@skip ObjectTrackingClass
74
@until };
75
76
ObjectTrackingClass全体はオブジェクト追跡するクラスのサンプルです。また、メンバ変数はTHEOLIZER_ANNOTATE()マクロによるオブジェクト追跡関連指定のサンプルです。<br>
77
- mIntメンバ変数はオブジェクト追跡するよう指定されたメンバ変数です。
78
- mShortメンバ変数はオーナー指定されたメンバ変数です。
79
80
<b>保存処理:(source/reference_and_test/basic2/test_object_tracking.cpp)</b>
81
82
@dontinclude basic2/test_object_tracking.cpp
83
@skip "tutoriseObjectTracking() start"
84
@skip {
85
@until aSerializer.clearTracking();
86
@until }
87
88
<div style="padding: 10px; margin-bottom: 10px; border: 1px solid #333333; border-radius: 10px; background-color: #d0d0d0;">
89
<b>makeAutoRelease()</b><br>
90
これはnewで獲得した領域を自動的にdeleteするためのヘルパー関数です。戻り値のインスタンスが解放されるタイミングでdeleteします。source/reference_and_test/basic/common.hで定義しています。たいへん小さいですので、興味のある方は覗いてみて下さい。
91
</div>
92
93
これにより、下図のようなデータ構造が生成され、図の順序でデータが保存されます。
94
95
@image html object_tracking1.png
96
97
<b>tutorise_object_tracking.json</b>ファイルは下記となります。
98
(//以下は説明のために書き込みました。)
99
100
{
101
"SerialzierName":"JsonTheolizer",
102
"GlobalVersionNo":1,
103
"TypeInfoList":[1]
104
}
105
1 // オブジェクトID=1へのポインタ(aLongPtr)
106
2 // オブジェクトID=2へのポインタ(aObjectTrackingClassPtr)
107
[1,100] // オブジェクトID=1のインスタンス(aLong)
108
[2,{ // オブジェクトID=2のインスタンス(aObjectTrackingClass)
109
"mInt":[3,200], // オブジェクトID=3のインスタンス(mInt)
110
"mShort":[4,300] // オブジェクトID=4のインスタンス(mShort)
111
}]
112
[5,101] // オブジェクトID=5のインスタンス(aLongOwner)
113
[6,"ObjectTrackingClass",{ // オブジェクトID=6のインスタンス(aObjectTrackingOwner)
114
"mInt":[7,201], // オブジェクトID=7のインスタンス(mInt)
115
"mShort":[8,301] // オブジェクトID=8のインスタンス(mShort)
116
}]
117
5 // オブジェクトID=5へのポインタ(aLongPtr2)
118
6 // オブジェクトID=6へのポインタ(aObjectTrackingClassPtr2)
119
7 // オブジェクトID=7へのポインタ(aIntPtr)
120
8 // オブジェクトID=8へのポインタ(aShortPtr)
121
122
<b>回復処理:(source/reference_and_test/basic2/test_object_tracking.cpp)</b><br>
123
元のデータ構造を回復できていることをチェックしています。
124
125
@skip 回復
126
@skip {
127
@until aSerializer.clearTracking();
128
@until }
129
130
131
<br>
132
//############################################################################
133
@section Polymorphism 2.ポリモーフィズムの使い方
134
//############################################################################
135
136
@subsection Polymorphism31 3-1.使い方
137
138
ポリモーフィックな基底クラスへのポインタをオーナ・ポインタとしてシリアライズすることで、ポリモーフィックに回復されます。つまり、派生クラスのインスタンスを基底クラスへのポインタでポイントして保存して回復した場合、派生クラスのインスタンスとして回復されます。
139
140
そのように動作させるために、2つの注意点があります。
141
142
1. 基底クラスは仮想関数を最低1つ持つ必要が有ります。<br>
143
これがないと、C++の仕様上、基底クラスへのポインタが指す派生クラスのインスタンスの型を動的に判定できないためです。<br>
144
<br>
145
146
2. 派生クラスはTHEOLIZER_REGISTER_CLASS()マクロで派生クラスであることを指定して下さい。<br>
147
基底クラスへのポインタ経由でシリアライズしたい派生クラスは必ず指定して下さい。<br>
148
指定漏れすると、シリアライズ処理する時に"Can not find the derived class for <基底クラス>."エラーになります。<br>
149
150
また、@ref Basic164 も参照下さい。
151
152
<b>サンプル用のクラス定義:(source/reference_and_test/basic2/test_polymorphism.h)</b>
153
154
@dontinclude basic2/test_polymorphism.h
155
@skip //-
156
@until THEOLIZER_REGISTER_CLASS((PolyDerived1));
157
158
<b>THEOLIZER_REGISTER_CLASS()</b>による派生クラスの指定を忘れないようにお願いします。<br>
159
また、クラス名を()で囲って指定する必要が有りますのでご注意下さい。
160
161
<b>保存処理:(source/reference_and_test/basic2/test_polymorphism.cpp)</b>
162
163
@dontinclude basic2/test_polymorphism.cpp
164
@skip "tutorisePolymorphism() start"
165
@skip {
166
@until aSerializer.clearTracking();
167
@until }
168
169
<b>回復処理:(source/reference_and_test/basic2/test_polymorphism.cpp)</b><br>
170
元のデータ構造を回復できていることをチェックしています。
171
172
@skip 回復
173
@skip {
174
@until aSerializer.clearTracking();
175
@until }
176
177
<b>tutorise_object_tracking.json</b>ファイルは下記となります。
178
179
{
180
"SerialzierName":"JsonTheolizer",
181
"GlobalVersionNo":1,
182
"TypeInfoList":[1]
183
}
184
[1,"PolyDerived0",{
185
"(PolyBase)":{
186
"mInt":100
187
},
188
"mShort":200
189
}]
190
[2,"PolyDerived1",{
191
"(PolyBase)":{
192
"mInt":1000
193
},
194
"mString":"string"
195
}]
196
197
メンバ変数名は"メンバ変数名"として記録されます。基底クラスにはメンバ変数名がないため、"{基底クラス名}"として記録しています。これにより、基底クラスの定義順序変更にも対応できます。
198
199
@subsection Polymorphism32 3-2.参照を経由する場合
200
201
ポリモーフィックな基底クラスへの参照をシリアライズすることで、ポリモーフィックに回復されます。つまり、派生クラスのインスタンスを基底クラス型の参照でポイントして保存し回復した場合、派生クラスのインスタンスとして回復されます。
202
203
<br>
204
//############################################################################
205
@section ClearTracking 3.オブジェクト追跡の仕組み
206
//############################################################################
207
208
@subsection HowToObjectTracking31 3-1.ポインタをシリアライズする仕組み
209
Theolizerはboost::serializationと同様にポインタをファイルへ保存し、そのファイルを回復した時、元のポイント構造を回復できる仕組みを実装しています。
210
211
下記のようなオブジェクト追跡処理により実現しています。
212
213
<b>・ポインタの保存</b><br>
214
1. オブジェクトIDテーブル<br>
215
インスタンスを保存する時に、インスタンスの先頭アドレスに対してオブジェクトIDを割り当て、インスタンスの先頭アドレスとオブジェクトIDの対応表を生成します。<br>
216
217
2. ポインタを保存<br>
218
ポインタの指すアドレスに対応するオブジェクトIDをオブジェクトIDテーブルで求め、オブジェクトIDを保存します。
219
220
<b>・ポインタの回復</b><br>
221
1. オブジェクトIDテーブル<br>
222
インスタンスを回復する時に、オブジェクトIDに対応するインスタンスの先頭アドレスを記録します。
223
224
2. ポインタを回復<br>
225
オブジェクトIDを読み出し、それに対応するインスタンスの先頭アドレスをオブジェクトIDテーブルで求め、インスタンスの先頭アドレスをポインタに設定します。
226
227
インスタンスは任意の「型」のインスタンスですが、これが構造体の場合、構造体全体の先頭アドレスと構造体の先頭メンバの先頭アドレスは一致します。(クラスの場合も同様です。)これらを纏めて1つのオブジェクトIDとすると適切に回復できないため、インスタンスの先頭アドレスだけでなく「型」も一緒に記録し、アドレスと型に対してオブジェクトIDを割り当てています。
228
229
<br>
230
@subsection HowToObjectTracking32 3-2.オブジェクト追跡の課題
231
ポインタを保存する前に必ずそのポインタが指すインスタンスを保存できれば特に問題はないのですが、そうとは限りません。<br>
232
233
ポインタの指すインスタンスが例えばローカル変数で、それがポインタより後でシリアライズ指示される場合もあります。<br>
234
そのようなデータ構造を回復するためには、そのローカル変数の保存は最初にポインタをシリアライズ指示された時ではなく、ローカル変数のシリアライズ指示まで遅らせるべきです。そうしないと順序よく回復できないため回復手順が複雑で負荷が高いものになります。<br>
235
236
しかし、ポインタが指している領域の所有権を当該ポインタが持っている場合は、最初にポインタをシリアライズ指示された時にインスタンスを保存すればOKです。最初にポインタを回復する際にインスタンス領域を確保して回復すれば適切にポイント構造を回復できますから。(*1)<br>
237
238
従って、ポインタがポイント先の所有権を持っているかどうかを判定できれば適切に保存/回復できるのですが、残念ながらシリアライズしようとしているポインタが所有権のある領域を指しているのか、そうでない領域を指しているのか判定する仕組みはC++言語仕様にはありません。
239
240
そこで、下記2つの選択肢を検討しました。
241
242
1. boost::serializationのようにこのようなケースをエラーとする(*2)<br>
243
この場合ローカル変数のようなインスタンスはそれをポイントするポインタより先に保存する必要が有ります。できれば避けたい制約と思います。
244
245
2. ポインタの属性として所有権の有無をプログラマが指定する
246
保存順序の制約はなく、処理負荷も特に高くはなりません。その代わりプログラマに少し負担がかかります。<br>
247
248
さて、インスタンスの所有権を持つか持たないかをポインタの属性とすることはリソース・リークし難いプログラムになりますのでたいへん好ましいと考えます。実際、C++11のスマート・ポインタは正にそのような概念に基づいています。スマート・ポインタが管理する領域はスマート・ポインタが所有権を持ち、その他のポインタは所有権を持ちません。所有権が明確ですのでメモリ・リークのリスクを大きく低減できます。<br>
249
250
そこで、インスタンスの所有権の有無をポインタの属性とする仕組みを実装することで、この問題を回避することにしました。<br>
251
252
<div style="padding: 10px; margin-bottom: 10px; border: 1px solid #333333; border-radius: 10px; background-color: #d0d0d0;">
253
(*1)ポインタが指すオブジェクトをオブジェクト追跡単位の最後で保存する案も検討しました<br>
254
途中でボイントされているローカル変数がシリアライズされたら、その時点で保存すれば良いです。制約も少なくプログラマへの負荷も小さいように見えます。<br>
255
しかし、最後までポイント先のインスタンスがシリアライズされなかった時、ユーザ・プログラムにおけるシリアライズ漏れ不具合なのか、所有権のある領域なのかの判断がつきません。前者の不具合は発見が遅れるとかなり痛いですので、この案は棄却しました。
256
</div>
257
258
<div style="padding: 10px; margin-bottom: 10px; border: 1px solid #333333; border-radius: 10px; background-color: #d0d0d0;">
259
(*2)boostの場合<br>
260
boost::serializationはこのような使い方を許可していません。上記ケースではローカル変数を保存する時にpointer_conflict例外が投げられます。<br>
261
["Pointer Conflict" Errors in the Boost Serialization Library](http://www.bnikolic.co.uk/blog/cpp-boost-ser-conflict.html)<br>
262
[Boost serialization with pointers](http://stackoverflow.com/questions/37747596/boost-serialization-with-pointers)
263
</div>
264
265
<br>
266
@subsection HowToObjectTracking33 3-3.オブジェクト追跡で用いる用語
267
このために、少し用語を定義しました。
268
269
1. 静的定義領域<br>
270
ポインタが所有権(獲得/解放する権限)を持つことができない領域です。下記があります。
271
- グローバル変数
272
- ローカル変数
273
- 他のクラスのメンバ変数(非ボインタ)
274
これは、例えばstruct Foo { int mInt; };のmIntです。ポインタ側からmIntを獲得/解放することができません。
275
276
2. 動的生成領域(*3)<br>
277
newやnew[]で獲得するインスタンスです。
278
279
3. ポインタ型<br>
280
通常のポインタです。これはポイント先のインスタンスの所有権を持ちません。<br>
281
静的定義領域、動的生成領域の両方をボイントすることができませ。<br>
282
283
4. オーナー・ポインタ型<br>
284
ポイント先のインスタンスの所有権を持っているポインタです。<br>
285
当然ですが動的生成領域のみポイント可能です。<br>
286
287
<div style="padding: 10px; margin-bottom: 10px; border: 1px solid #333333; border-radius: 10px; background-color: #d0d0d0;">
288
(*3)「静的定義領域」と言う名称<br>
289
以前、teratailで「[インスタンス生成方法の呼び方について](https://teratail.com/questions/20206)」質問し、catsforepawさんの回答を元に決定しました。<br>
290
遠いところからですが、catsforepawさん、その節はありがとうございました。
291
</div>
292
293
<br>
294
@subsection HowToObjectTracking34 3-4.オブジェクト追跡対象について
295
静的定義領域は、全てのシリアライズ対象の変数がオブジェクト追跡候補になります。しかし、実際にポインタでポイントされる変数はその内の一部だけですので、全てをオブジェクト追跡するのは無駄が多いです。そこで、@ref Basic21 で示した方法でオブジェクト追跡対象を絞り込んでいます。
296
297
<br>
298
@subsection HowToObjectTracking35 3-5.オブジェクト追跡単位について
299
@ref Basic22 に示したオブジェクト追跡単位について少し詳しく説明します。
300
301
これはオブジェクトIDテーブルの有効期間です。clearTracking()することで
302
303
1. オブジェクトIDテーブルにシリアライズされていないインスタンスが登録されていないか確認します
304
2. オブジェクトIDテーブルをクリアします
305
306
前者により、ユーザ・プログラムのバグ検出をサポートします。<br>
307
後者により、不要なオブジェクト追跡を解除できるのでバフォーマンスを改善できます。<br>
308
309
<div style="padding: 10px; margin-bottom: 10px; border: 1px solid #333333; border-radius: 10px; background-color: #d0d0d0;">
310
<b>注意事項1:</b><br>
311
解放したインスタンスを追跡したままにしていると未定義メモリ・アクセスが発生する場合があります。ですので、clearTracking()するまで、もしくは、シリアライザ自身を破棄するまで下記インスタンスを破棄しないで下さい。<br>
312
・シリアライズしたインスタンス<br>
313
・シリアライズしたポインタが指すインスタンス<br>
314
なお、clearTracking()することで「シリアライズした」と言う記録が全て破棄されますので、必要であれば、cleartTracking()後、最初のシリアライズまでの間ならばインスタンスを安全に破棄できます。
315
</div>
316
317
<div style="padding: 10px; margin-bottom: 10px; border: 1px solid #333333; border-radius: 10px; background-color: #d0d0d0;">
318
<b>注意事項2:</b><br>
319
clearTracking()により、未解決なオブジェクト追跡(ポインタが登録されたがポインタの指すインスタンスが保存/回復されていない)の有無を確認します。もし、未解決なオブジェクト追跡がある時、WrongUsingエラーを通知します。(「@ref ErrorReport 」参照)<br>
320
なお、オブジェクト追跡を行い、かつ、clearTracking()を呼び出していない場合、シリアライザ・インスタンスのデストラクタでプログラムを異常終了させています。オブジェクト追跡する場合は必ずデストラクトする前にclearTracking()を呼び出すようにして下さい。</div>
321
322
<br>
323
//############################################################################
324
@section TestObjectTracking 4.オブジェクト追跡の網羅的な使用例(自動テスト)の説明
325
//############################################################################
326
327
@subsection TestObjectTracking41 4-1.各種メモリへのポインタのテスト
328
@subsubsection TestObjectTracking411 4-1-1.概要
329
330
ここでは、C++で用いられる少し異なるメモリ上のインスタンスへのポインタが適切に回復されることをテストしています。具体的には下記の通りです。
331
332
1. グローバル変数<br>
333
ここには静的定義領域のみ存在できますので、ここへのポインタをオーナー指定できません。<br>
334
335
2. ローカル変数(スタック変数)<br>
336
ここも静的定義領域のみ存在できますので、ここへのポインタをオーナー指定できません。<br>
337
338
3. ヒープ変数<br>
339
ここには動的生成領域と静的定義領域の両方が存在できます。newで獲得したクラスのインスタンス全体は動的生成領域です。そのクラスの各メンバ変数は静的定義領域となります。基底クラスは少し複雑です。<br>
340
341
- ポリモーフィックな(仮想関数がある)クラスの場合<br>
342
基底クラスへのポインタ経由でdeleteできますので、基底クラスへのポインタをオーナー指定できます。<br>
343
<br>
344
345
- 非ポリモーフィックな(仮想関数がない)クラスの場合<br>
346
C++仕様上、基底クラスへのポインタ経由でdeleteすると派生クラスのデストラクタは呼ばれず基底クラスとしてデストラクトされます。従って、非ポリモーフィックなクラスの場合、その基底クラスへのポインタをオーナー指定してはいけません。<br>
347
348
下記組み合わせのインスタンスとポインタ(非オーナー)について保存/回復テストを行います。<br>
349
350
静的定義領域(グローバル変数, ローカル変数, メンバ変数) + 動的生成領域(プリミティブ, クラス)
351
×
352
Pointee指定プリミティブ型(long) + Pointee指定なしクラス型(ObjectTracking0) + Pointee指定クラス型(ObjectTracking1)
353
354
また、2番目以降の基底クラス・ポインタは一般にインスタンス先頭ではないアドレスを指しますが、このケースにも対応できていることを確認します。
355
そのために、派生クラスのインスタンス、および、その2番目の基底クラスへのポインタをシリアライズし、ポインタが回復したインスンタスをポイントすることを確認しています。
356
357
更に、動的生成領域(クラス)へのポインタ(非オーナー)のテストを実施する際に、std::shared_ptr<>を非侵入型手動対応しました。その時、[std::shared_ptr<>対応は意外に難しい](https://github.com/yossi-tahara/Theolizer/issues/18)ことが分かり、いくつか複雑な対応を行いましたので、ここでその一部のテストも行っています。(後日、標準コンテナ対応する予定です。その時、網羅的な自動テストを実装します。)
358
359
@subsubsection TestObjectTracking412 4-1-2.ソース・コード
360
361
<b>source/reference_and_test/basic2/test_object_tracking.h</b>でテスト用のクラスを定義してます。<br>
362
363
1. 2番目以降の基底クラスへのポインタの回復テスト用
364
- ObjectTrackingBase0 1番目の基底クラス
365
- ObjectTrackingBase1 2番目の基底クラス
366
- ObjectTrackingDerived 上記2つを継承したクラス<br>
367
<br>
368
369
2. 各種メモリへのポインタのテスト用
370
- ObjectTracking0 被ポイント指定(Pointee)なし
371
- ObjectTracking1 被ポイント指定(Pointee)あり
372
- StaticDefinition メンバ変数静的定義領域用
373
- Pointers 自動シリアライズするポインタの定義<br>
374
<br>
375
376
3. 同じインスタンスを複数回シリアライズした時のテスト用
377
上記で定義したObjectTrackingDerivedを用います。
378
379
<b>source/reference_and_test/basic2/test_object_tracking2.cpp</b>でテスト関数を定義してます。<br>
380
381
1. 保存処理<br>
382
template<class tSerializer><br>
383
void saveObjectTracking(tSerializer& iSerializer)の前半<br>
384
<br>
385
386
2. 回復処理<br>
387
template<class tSerializer><br>
388
void loadObjectTracking(tSerializer& iSerializer)の前半<br>
389
390
391
@subsection TestObjectTracking42 4-2.ポインタ(非オーナー)のテスト
392
@subsubsection TestObjectTracking421 4-2-1.概要
393
ポインタのシリアライズ、および、ポイント先のインスタンスのシリアライズについて、指定方法が手動(トップ・レベル)、自動シリアライズ(自動型のメンバ変数)、手動(非トップ・レベル)の3種類あります。それぞれについて各種の型、および、ポインタ→インスタンスとインスタンス→ポインタの順序おのおのの組み合わせのテストを行います。
394
395
ポインタ:
396
手動(トップ・レベル) + 自動シリアライズ(自動型のメンバ変数) + 手動(非トップ・レベル)
397
×
398
インスタンス:
399
手動(トップ・レベル) + 自動シリアライズ(自動型のメンバ変数) + 手動(非トップ・レベル)
400
×
401
全てのプリミティブ + enum型 + scoped num型 + クラス + 各配列型
402
×
403
ポインタを先に保存 + インスタンスを先に保存
404
405
@subsubsection TestObjectTracking422 4-2-2.ソース・コード
406
407
<b>source/reference_and_test/basic2/test_object_tracking.h</b>でテスト用のクラスとマクロを定義してます。<br>
408
409
1. DEFINE_MEMBERS()マクロ<br>
410
各種の型に対応する、変数宣言や初期化を定義するためのマクロです。@ref SingleTest と同じ名前ですが、少し異なるマクロです。定義している変数の型は同じですが、初期化値が異なります。<br>
411
<br>
412
413
2. PointeeListクラス<br>
414
静的定義領域の定義です。各型のインスタンスについて、自動シリアライズと手動(トップ・レベル)を担います。前者は非侵入型完全自動として処理し、後者はsavePointee()とloadPointee()関数で行います。<br>
415
<br>
416
417
3. PointeeListManualクラス<br>
418
静的定義領域の定義です。各型のインスタンスについて、手動(非トップ・レベル)を担います。<br>
419
<br>
420
421
4. PointerListクラス<br>
422
ポインタ(非オーナー)の定義です。各型のポインタについて、自動シリアライズと手動(トップ・レベル)を担います。前者は非侵入型完全自動として処理し、後者はsavePointer()とloadPointer()関数で行います。トップ・レベル、および、自動型については、例えばデバッグやログ用にconst領域へのポインタの保存を想定して、constポインタも定義しています。<br>
423
<br>
424
425
5. PointerListManual<br>
426
ポインタ(非オーナー)の定義です。各型のポインタについて、手動(非トップ・レベル)を担います。回復処理を行わない手動型の実装は想定不要と考えますので、constポインタを定義していません。<br>
427
<br>
428
429
<b>source/reference_and_test/basic2/test_object_tracking2.cpp</b>でテスト関数を定義してます。<br>
430
431
1. 保存処理<br>
432
template<class tSerializer><br>
433
void saveObjectTracking(tSerializer& iSerializer)の後半<br>
434
<br>
435
436
2. 回復処理<br>
437
template<class tSerializer><br>
438
void loadObjectTracking(tSerializer& iSerializer)の後半<br>
439
440
441
@subsection TestObjectTracking43 4-3.オーナー・ポインタのテスト
442
@subsubsection TestObjectTracking431 4-3-1.概要
443
オーナー・ポインタのシリアライズについて、指定方法が手動(トップ・レベル)、自動シリアライズ(自動型のメンバ変数)、手動(非トップ・レベル)の3種類あります。それぞれについて各種の型の組み合わせのテストを行います。また、nullptrの回復もテストします。<br>
444
(ポインタ(非オーナー)と異なり、インスタンス側はポインタが管理するため組み合わせが発生しません。また、インスタンスの保存は先に出現した方が先ですので、保存順序の組み合わせも発生しません。)
445
446
オーナー・ポインタ:
447
手動(トップ・レベル) + 自動シリアライズ(自動型のメンバ変数) + 手動(非トップ・レベル)
448
×
449
全てのプリミティブ + enum型 + scoped num型 + クラス + 各配列型
450
451
@subsubsection TestObjectTracking432 4-3-2.ソース・コード
452
453
<b>source/reference_and_test/basic2/test_object_tracking.h</b>でテスト用のクラスとマクロを定義してます。<br>
454
455
1. DEFINE_MEMBERS()マクロ<br>
456
ポインタ(非オーナー)と共通です。<br>
457
<br>
458
459
2. NEW_ARRAY()マクロ<br>
460
C++は、配列型(Type[N])をnewした結果は残念なことに配列型へのポインタ(Type(*)[N])にならず要素へのポインタ(Type*)になります。そのため、配列型へのポインタ(Type(*)[N])変数へそのままでは代入できません。これをreinterpret_cast<Type(*)[N]>()して(*4)代入できるようにするマクロです。<br>
461
<br>
462
463
3. OwnerListクラス<br>
464
オーナー・ポインタの定義です。各型のポインタについて、自動シリアライズと手動(トップ・レベル)を担います。前者は非侵入型完全自動として処理し、後者はsavePointer()とloadPointer()関数で行います。インスタンスを回復しないオーナー指定ポインタは意味がないので、constポインタは定義していません。<br>
465
<br>
466
467
4. OwnerListManualクラス<br>
468
オーナー・ポインタの定義です。各型のポインタについて、手動(非トップ・レベル)を担います。OwnerListクラスと同様constポインタを定義していません。<br>
469
<br>
470
471
<div style="padding: 10px; margin-bottom: 10px; border: 1px solid #333333; border-radius: 10px; background-color: #d0d0d0;">
472
(*4)「配列型へのポインタ」のサポート<br>
473
以前、teratailで「[配列型(サイズ含む)へのポインタをnewで生成したい](https://teratail.com/questions/34266)」旨を質問してraccyさんの回答をヒントに対応できました。<br>
474
遠いところからですが、raccyさん、ありがとうございました。
475
</div>
476
477
<b>source/reference_and_test/basic2/test_object_tracking3.cpp</b>でテスト関数を定義してます。<br>
478
479
1. 保存処理<br>
480
template<class tSerializer><br>
481
void saveObjectTracking3(tSerializer& iSerializer)の前半<br>
482
<br>
483
484
2. 回復処理<br>
485
template<class tSerializer><br>
486
void loadObjectTracking3(tSerializer& iSerializer)の前半<br>
487
488
@subsection TestObjectTracking44 4-4.同じインスタンスを複数回シリアライズするテスト
489
490
ObjectTrackingDerivedのインスタンスに対して、被ポインタ指定したものとしていないものについて保存/回復テストを行います。
491
492
<b>source/reference_and_test/basic2/test_object_tracking3.cpp</b>でテスト関数を定義してます。<br>
493
494
1. 保存処理<br>
495
template<class tSerializer><br>
496
void saveObjectTracking3(tSerializer& iSerializer)の後半<br>
497
<br>
498
499
2. 回復処理<br>
500
template<class tSerializer><br>
501
void loadObjectTracking3(tSerializer& iSerializer)の後半<br>
502
503
また、同じインスタンスを複数回保存し、それを異なるインスタンスへ回復しようとした時、WrongUsing例外が発生することのテストを行います。
504
505
<b>source/reference_and_test/basic2/test_object_tracking.cpp</b>でテスト関数を定義してます。<br>
506
507
tutoriseObjectTracking()関数の最後の方、「複数回シリアライズ・データの回復エラーテスト」で行っています。<br>
508
509
<br>
510
//############################################################################
511
@section TestPolymorphism 5.ポリモーフィズムの網羅的な使用例(自動テスト)の説明
512
//############################################################################
513
514
ここでは、基底クラスへのポインタでポイントされる異なる派生クラスを適切に回復できることを確認します。<br>
515
非侵入型完全自動、侵入型半自動、非侵入型手動の3種類の基底クラスと派生クラスを用意し、派生クラスは3種類の基底クラスを全て継承しました。
516
517
<b>source/reference_and_test/basic2/test_polymorphism.h</b>でテスト用のクラスを定義してます。<br>
518
519
1. 基底クラス
520
- PolyBaseFullAuto 非侵入型完全自動
521
- PolyBaseHalfAuto 侵入型半自動
522
- PolyBaseManual 非侵入型手動<br>
523
<br>
524
525
2. 派生クラス
526
- PolyDerivedFullAuto 非侵入型完全自動
527
- PolyDerivedHalfAuto 侵入型半自動
528
- PolyDerivedManual 非侵入型手動
529
530
<b>source/reference_and_test/basic2/test_polymorphism.cpp</b>でテスト関数を定義してます。<br>
531
532
1. 保存処理<br>
533
template<class tSerializer><br>
534
void savePolymorphism(tSerializer& iSerializer)<br>
535
<br>
536
537
2. 回復処理<br>
538
template<class tSerializer><br>
539
void loadPolymorphism(tSerializer& iSerializer)<br>
540
541
基底クラスのインスタンスをstd::unique_ptr<>で保持し、そのstd::unique_ptr<>のリストをstd::vector<>で保持しています。(std::vector<>とstd::unique_ptr<>を非侵入型手動クラスとして仮にシリアライズ対応しています。)<br>
542
3種類の基底クラス毎にstd::vector<>を用意しているので、std::vector<>も下記の3種類あります。
543
544
- 非侵入型完全自動
545
- 侵入型半自動
546
- 非侵入型手動
547
548
各std::vector<>には3種類の派生クラスのインスタンスを登録して、std::vector<>を保存します。そして、全てのポインタをnullptr設定して回復し、保存した時の派生クラスを回復できたことを確認しています。<br>
549
550
*/
Theolizer
source
document
ja
7c.object_tracking.h
© 2016
Theoride Technology
All Rights Reserved. "Theolizer" is a registered trademark of Theoride Technology.
構築:
1.8.12