-
Notifications
You must be signed in to change notification settings - Fork 5
Description
単純に回復すれば良いと思っていたのですが、複数回保存して回復した時、参照カウンタが回復できません。
boostのshared_ptrのシリアライズ・コードを確認したところ、この問題に対策されてました。
シリアライズしたshared_ptrをシリアライズする際、shared_ptrの追跡テーブルをstd::mapにて別途管理してました。firstはオブジェクトのアドレス、secondはshared_ptr自身です。
しかし、実装は意外に複雑です。
-
2番目以降の基底クラスへのポインタと派生クラス・オブジェクトのポインタはアドレスが一致しません。
なので、shared_ptr追跡テーブルへは派生クラス・オブジェクトのアドレスを登録しています。 -
更に回復処理時、aliasingコンストラクタを使っています
これは、元のshared_ptrと参照カウンタ、および、デリート処理(デリート先オブジェクトとデリータ)を共有しているがポイント先を自由に選択できるshared_ptrのコントラクタです。ポイント先の寿命が元の寿命以上の場合に使えます。
なぜ、aliasingコンストラクタを使っているのか非常に不思議だったのですが、この対策は近藤貴俊氏が行っていて丁寧に解説されていました。
簡単に説明すると、派生クラスへのポインタを管理しているshared_ptrと、それと同じインスンタスを2番目以降の基底クラスへのポインタで管理しているshart_ptrの2つを保存し、回復した時に不具合が出るのです。
shared_ptr追跡テーブルはshared_ptr<派生クラスの型>を使うことも可能な筈ですが、boostはstd::shared_ptr<void>型で管理しています。
そのため、std::mapに登録されているshared_ptrを単純に返却すると、基底クラスへのポインタに派生クラスのアドレスが設定され、ずれてしまいます。
この問題を回避するために、aliasingコンストラクタをうまいこと使っていました。(これを使わないと複雑なことになりそうです。)
この2点の対処を実装する予定です。