スマポと相互参照
GCを持っていない以上、根本的にC++のスマポと循環参照は相性が悪いけど、私が問題にしたいのはソコではないです。
例えば、前回公開したSVDライブラリだと以下の様に、木構造の情報を構成します。
- デバイスはペリフェラルを複数保持する
- ペリフェラルはレジスターを複数保持する
- レジスタ―はフィールドを複数保持する
ただ保持しているだけなら、vector<レジスタ>か、vector<unique_ptr<レジスタ>>でいいでしょう。 ですが、SVDのデータ構造は、フィールドの情報を確定するにはレジスターの情報が必要である、という様に、子→親への参照も必須なのです。
(むろん、木構造の構築時に確定してしまっても良いけど。実際、最初に作ったときは、どうせ編集するつもりがないので確定して作った。この場合、子が親を必要としないので、単にvectorで困ることはないないばーですね。)
で、今更生ポインタ(ナマポ?)で管理ってのもあれなので、スマポ使いましょう。相互参照するので、shared_ptrとweak_ptrを使えばいいのでしょうか?
しかし、これだと問題が発生します。それは親ポインタ(オヤポ?)をいつ確定するのってことです。
struct device { vector< share_ptr< peripheral> > peripheral; device():list{} { peripheral . emplace_back( new peripheral(this) ); } } struct peripheral { week_ptr< device > parent; // オヤポ vector< share_ptr <register> > registers; peripheral( week_ptr< device> オヤポ? ) parent( オヤポ? ), registers{} { registers . emplace_back( new field(this) ); } }; struct register { week_ptr< peripheral > parent; // オヤポ vector< share_ptr <field> > fields; };
オヤポ?とか書いてるところがネックです。
ナマポだったら、コンストラクタにthisを渡せば済むことが、スマポだと、コンストラクタで完結できないなさそうです。次の様な関数を定義するなりして、後で呼び出すしかない。
struct device { void set_parent ( std::share_ptr< device > ptr) { for(auto p: peripherals) p-> set_parent( ptr, p); } }; struct peripheral { void set_parent ( std::share_ptr< device > ptr, std::shared_ptr<peripheral> me) { parent = ptr; for(auto p: registers) p-> set_parent( me, p); } };
もしくは、諦めて、親への参照はナマポにするか。
今回の場合なんかは、そもそも、親への参照が壊れたら正常に動かないので、ソコを気にしない(ユーザー責任)というのは一つの答えとして悪くない気がします。
struct device { vector< unique_ptr< peripheral> > peripheral; device():list{} { peripheral . emplace_back( new periphera( *this ) ); } } struct peripheral { private: device& parent; // オヤポ public: vector< unique_ptr <register> > registers; peripheral( device& d ) parent( d ), registers{} { registers . emplace_back( new register(*this) ); } }; struct register { private: peripheral& parent; // オヤポ public: vector< unique_ptr <field> > fields; };
うーむ………。Java何かだと一切悩まない様なところで、変に悩むのがC++ですな。
一般にはどうするのが良い手段なんだろうね。