• 締切済み

参照メンバを持つクラス

ClassAとClassBにCMyDataオブジェクトを渡したいのですが、メモリ上に同じデータのコピーを作りたくないので、コンストラクタがCMyDataの参照を受け取る設計にしました。こうすることで、CMyDataの実体はメモリ上に1つしか存在しないことになります。 ただ、クラスが、自身が管理していない外部領域にあるデータへの参照を使って仕事をするというのに違和感を感じます。 完全コンストラクタというデザインパターンがあって、クラスのインスタンスを生成する時に必要な全てのデータを渡すのが正しい流儀だそうです。 しかしこのClassA(B)の設計では、ClassA(B)の寿命が終わるまで参照先のデータが生きているとは限りません。もっといい設計はないでしょうか?ちなみにCMyDataは実際にはかなり大きなデータで、一時的であってもコピーを複数持ちたくないのです。ClassAとClassBは、実際は他のデータも参照するため1つのクラスにはしたくないのです。 class CMyData { // 色々なデータ }; class CMain { CMyData* myData; // ファイルからデータを読み込んで生成 ClassA* objA; ClassB* objB; void ReadFile() { myData = new CMyData(); // ファイルからデータを読み込みCMyData構築 } void Init() { ReadFile(); objA = new ClassA(*myData); // 自身のメンバ変数の参照でClassAを構築 objB = new ClassB(*myData); } void DoProcess() { Init(); // 実行は一度だけ objA->hoge(); // ClassAに仕事をさせる objB->foo(); // ClassBに仕事をさせる } } class ClassA { CMyData& m_data; public: ClassA(CMyData& data) m_data=data; // CMyDataオブジェクトを参照で受け取る void hoge(); } class ClassB { CMyData& m_data; public: ClassB(CMyData& data) m_data=data; // CMyDataオブジェクトを参照で受け取る void foo(); }

みんなの回答

  • mitoneko
  • ベストアンサー率58% (469/798)
回答No.2

 ある程度、グローバルな領域で管理する必要があるデータ・オブジェクトを可能な限り、他のクラスからの依存性を引き下げるための1つの方法だとは思います。  昔から使われている領域の1つは、文字列ですね。参照回数管理型の文字列実装は良く聞きませんか?  文字列は、あちこちのクラスに引き渡されます。どこで開放されるか、どこで確保されたかなんて、わからないくらいあっちこっちに飛び火します。普通は、コピーを持ちたくなるわけですが、これを嫌って1つのインスタンスでと考えると、とたんにあっちこっちのクラスと依存関係を持つ羽目になる。下手すると、他のクラス間の依存関係にまで発展する・・・しかも、えてして、巨大になりがちなオブジェクト。そう、まさに、あなたがやろうとしているCMyDataとそっくりな、代物ですね。  参照回数管理型の文字列というのは、良く聞くし、他の言語ではそれが組み込み文字列型の標準実装になっている言語も多いですね。  少なくとも、一般的な解決方法の1つなのだとは思います。(ベストかどうかは、私にはわかりかねますが・・・)  

katorea21
質問者

お礼

MFCのCStringは確かそのような実装になっていると聞いたことがあります。メンバは文字列へのポインタだけで、sizeof(CString)は常に4バイトになっています。これと同じイメージで、ポインタだけを安全な形で引き回せば良いのですね。

  • mitoneko
  • ベストアンサー率58% (469/798)
回答No.1

 これは、動的メモリーを使用して、(C++のnewで作成したインスタンスも含みます。)メモリーを確保した時の、よくある各種悩みの1パターンです。  さて、良くある悩みなので、対応する手段もいくつかあります。  手っ取り早いのは、C++11で標準実装された(それ以前のC++であれば、boostライブラリーなどで実装されています。)、スマートポインターの利用でしょう。  このポインターは、自分の寿命をポインター自身が管理して、後始末は、ポインター自らが行えば良いという発想で作成されている、テンプレートクラスです。  今回の場合は、std::shared_ptr (boost::shared_ptr) を利用するとスムーズかな。これは、ポインターの参照回数をポインター自身が管理し、参照回数が0になった時に、自分自身を解放するように設計されています。  CMyDataのshared_ptrを作成して、これを各クラスに渡しておけば、CMyDataをクラス外部で開放しても、クラスAやクラスBのインスタンスが生きている限りCMyDataの生存が保証されます。  スマートポインターで検索してみると、使い方は、懇切丁寧に解説したサイトがいっぱいあるので、詳細は、そっちに譲ります。

katorea21
質問者

お礼

ご回答ありがとうございます。 スマートポインタを使えば外部のデータを安全に参照できるということですね。scoped_ptrは使ったことがありますがshared_ptrについても勉強してみます。 CMyDataに対する操作を複数のクラスに分けて実装する場合、このようなデザインパターンは標準的なのでしょうか。