プログラムdeタマゴ

nodamushiの著作物は、文章、画像、プログラムにかかわらず全てUnlicenseです

C++の相互参照ってどう作るのが良いの?

スマポと相互参照

 GCを持っていない以上、根本的にC++のスマポと循環参照は相性が悪いけど、私が問題にしたいのはソコではないです。

 例えば、前回公開したSVDライブラリだと以下の様に、木構造の情報を構成します。

  1. デバイスはペリフェラルを複数保持する
  2. ペリフェラルはレジスターを複数保持する
  3. レジスタ―はフィールドを複数保持する

 ただ保持しているだけなら、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++ですな。

 一般にはどうするのが良い手段なんだろうね。