• 締切済み

参照型を格納できるコンテナについてなど

ちょっと長文です。下のほうに質問があります。 STLのvectorコンテナを使用しているのですが、 困った事態が発生しています。 自分は、参照型を要素として、持たしたいのですが、 持たすことができません。 なにやら調べてみたところ、STLのコンテナクラスというのは 基本的に「値ベースのコンテナ」らしく、「参照ベースのコンテナ?」 としてコンテナを使うには、ポインタ型を格納して下さい。との ことでした。 ただし、この方法は2重deleteが発生する危険性を孕んでいるので、 Boostのなんかのポインタークラス?のようなものを使えば、 そのような問題に悩まされることないですよー。とありました。 ここで問題なのは、 ・Boostを扱えるだけの知識がない。 ・そもそもBoostを使えるまで環境設定できる自信がない。 ということです。 そのため、普通のポインタを使って実装しようと思うのですが、 そして上記のような問題が出てくるにつれ自分の中では 次のような疑問点が出てきました。 ●質問(1) ・なんで参照型を格納できるコンテナがないのよ!  本当はあったりするんだけども、自分が知らないだけ? ●質問(2) ・関数間でオブジェクトを渡すときには、パフォーマンスとかも  考慮してもconstキーワードを使いつつの参照渡しがよい。と  Effective C++か何かで読んだのですが、コンテナに格納する  場合にはこれは有効ではないのか?  また、オブジェクトは、基本的には、やたらめったら  コピーするものではなく、一つオブジェクト用のメモリ領域を  作ったらそれを流用(ポインタ・参照を使って参照する)した方が、  作り的にきれいな気がするのですが、なにか方針とかあったりする  のでしょうか? 以上長くなってしまいましたが、よろしくお願いいたします。

みんなの回答

回答No.1

 こんばんは。 ●質問(1)  STLコンテナの内部にある  typedef typename T& reference;  で、Tの形が何かしらの参照であった場合、  typedef typename T&& reference;  となり、コンパイルエラーになります。  何故参照を出来るコンテナが無いのかは私にも分かりません。飽くまで推測ですが「想定外」だったのではないでしょうか。  TR1のリファレンスラッパーは正しく参照をコンテナにしまう為の物ですが、随分と大袈裟な代物です。  http://www.aristeia.com/EC3E/TR1_info.html  これ位ならば、自身で作成してしまった方が手っ取り早いでしょう。 ●質問(2)  当然、オブジェクトがコンテナよりも寿命が長いのであるならば参照も有効でしょう。  しかしそれよりは動的に作成したオブジェクトのポインタを入れる事の方が良く有る様です。  std::vector<XXX*> v(1, new XXX());  しかし↑の状態では「v」が別の場所に複写され(v2とする)「v2」が「v」よりも寿命が長い場合、XXX*をdeleteする責任は「v2」の方に発生します。  ここで間違えて「v」側でXXX*にdeleteをかけてしまうと、それよりも寿命の長い「v2」で「消去済み」のポインタに触る事になります。  その為に、参照カウント式のスマートポインタ等を使用したりします。  std::vector<smart_ref_pointer<XXX> > v(1, smart_ref_pointer<XXX>(new XXX()));  参照カウント式のスマートポインタは、コピーや代入に反応してカウントを上げて行き、デストラクタでカウントを下げます。寿命の問題に呪われる事の多くは回避出来ます。  以下は簡単なリファレンスラッパーです。 #include<vector> struct CVoidPtrBase { protected: explicit CVoidPtrBase(const CVoidPtrBase& r) : m_p(r.m_p){ } explicit CVoidPtrBase(const void* p) : m_p(const_cast<void*>(p)){ } CVoidPtrBase& operator=(const CVoidPtrBase& r) { if(this != &r)new (this) CVoidPtrBase(r); return *this; } void* get(){ return m_p; } const void* get() const { return m_p; } private: void* m_p; }; template<class __TP> struct CRefWrapper : private CVoidPtrBase { typedef typename CRefWrapper<__TP> _Self; typedef typename __TP value_type; typedef typename __TP* pointer; typedef typename __TP& reference; typedef typename const __TP* const_pointer; typedef typename const __TP& const_reference; CRefWrapper(const _Self& r) : CVoidPtrBase(r){ } explicit CRefWrapper(const_pointer p) : CVoidPtrBase(p){ } explicit CRefWrapper(const_reference r) : CVoidPtrBase(&r){ } _Self& operator=(const _Self& r) { if(this != &r)CVoidPtrBase::operator=(r); return *this; } operator reference(){ return *get(); } operator const_reference() const { return *get(); } private: pointer get(){ return static_cast<pointer>(CVoidPtrBase::get()); } const_pointer get() const { return static_cast<const_pointer>(CVoidPtrBase::get()); } }; struct CTest { explicit CTest(int i) : m_i(i){ } CTest(const CTest& r) : m_i(r.m_i){ } CTest& operator=(const CTest& r) { if(this != &r)new (this) CTest(r); return *this; } private: int m_i; }; //お試しと確認 int main() { CTest test(5); ::printf("%p\n", &test); std::vector<CRefWrapper<CTest> > v(1, CRefWrapper<CTest>(test)); const CTest& refTest = v[0]; ::printf("%p\n", &refTest); CRefWrapper<CTest> refWrapper = v[0]; ::printf("%p\n", &static_cast<CTest&>(refWrapper)); CTest test2(150); ::printf("%p\n", &test2); const CRefWrapper<CTest> refWrapper2(test2); ::printf("%p\n", &static_cast<const CTest&>(refWrapper2)); refWrapper = refWrapper2; ::printf("%p\n", &static_cast<CTest&>(refWrapper)); return 0; }

upanepa
質問者

お礼

ご回答ありがとうございます。 頂いたソースですが、 Borland C++ Compiler 5.5でも、codepadのおそらくgccでも コンパイルエラーが出てしまいました。。 Microsoft Visual Studio 2005でならコンパイルできましたが、 現時点の自分の読み取り能力ではちょっと解読できませんでした>< どのような場合に生のポインタを用いたコンテナを使ったときに 問題になるのかをもう一度整理してみようと思います。 また参照カウント式のスマートポインタを使ったときに、 内部がどのような動きになるのかについても考えてみます。 その上でどうしても今作ろうとしているものに参照カウント式の スマートポインタを使ったほうがよいのかを判断しようと思います。

関連するQ&A

  • クラスとSTLコンテナについて

    使用しているコンパイラおよびSTLはVisual Studio 2008 Professional付属のものです C++にてSTLのコンテナにクラスオブジェクトを入れて使用しようと考えています しかし、オブジェクトをコンテナへ挿入・削除した際に何度もコピーコンストラクタが呼び出されているのを確認しました コンテナ内に直接、比較的大きめのリソースを持つオブジェクトを多数入れた場合、オブジェクトのコピーだけでパフォーマンスに影響が出るのではないか、と感じました これはコンテナを使う上では許容しないといけないことなのでしょうか? クラスオブジェクトを直接ではなく、ポインタで入れた場合は、コンテナ削除時にデストラクタが呼ばれないため、クラスポインタとコンテナの組み合わせはしてはいけないと認識しています クラスとコンテナを組み合わせて使用する場合は、boostのshard_ptrを使用するのが、パフォーマンスを考慮する上では最も良い選択なのでしょうか? それとも、それ以外の常識的な使用方法があるのでしょうか? 回答よろしくお願いします

  • 可変長配列に格納されたオブジェクトの参照

    「name」、「sex」などのデータがあり、 そのデータをHumanオブジェクトとして、可変長配列(humanArray)に格納してあります。 humanArray.add( new Human( name, sex ) );  // このような感じでしょうか。 標準入力から「name」が入力されると、オブジェクトを参照し、 HumanArrayに格納されているHumanオブジェクトの「name」データを一つ一つ比較して、 一致したら配列の要素をすべて出力する。 というプログラムを作りたいのです。 問題としているのは、 一致するかの照合処理を別のクラスで行うので、 nameを処理を行うクラスに渡す必要がありますが、 可変長配列のi番地に入っているオブジェクトのnameを 得るための方法がわかりません。 Humanクラスに public static String throwName() { return name; } のようなクラスを作って、 処理を行うクラスで、 String name = humanArray.get(i).throwCode(); というような処理を行うイメージなのですが・・・。 どのようにすれば良いのかご教授ください。 どのように質問をすれば良いのかも良くわからないので情報が少ないやもしれません その時は遠慮なく「追加情報が欲しい。」と仰ってください。 例 -----配列の内容----- 阿部 男 -------------------- 馬場 女 -------------------- 千葉 女 -------------------- 標準入力:馬場(name) -------Humanクラスの内容-------- class Human { private String name; private String sex; public Human( String nm, String s ) { name = nm; sex = s; } public static void showArticle() { System.out.println(name); System.out.println(sex); } }

    • ベストアンサー
    • Java
  • 循環参照の問題に関して。

    現在設計の段階なのですが、あるクラスが循環参照に陥りそうで実装に踏み切れません。 現在の状況で循環参照の問題が発生するのか、またどのような開発が循環参照の問題になるのか、教えていただきたいと思います。 現在の状況は、 mainにControlというクラスが実体で多重度1で持たれている。 ControlにDeviceというクラスが多重度0..nでポインタでもたれている。 DeviceというクラスはControlというクラスの参照を持つ。 このような状況になっています。 問題の関係はControlとDeviceです。 このような状況に詳しい方がいらっしゃいましたら、回等をお願いいたします。

  • サーブレットコンテナのメモリ解放について

    お世話になっております。 今回質問させていただきたいのはサーブレットコンテナ上のメモリ解放についてです。サーブレットの動作フローとしては、 (1)クライアントからHTTPリクエストが投げられる。 (2)Webサーバがリクエストを受け取り、コンテナへリクエストを委譲する。 (3)サーブレットコンテナは、リクエストとレスポンスのラッパーオブジェクトを生成し、リクエストへリクエスト情報をマッピングする。 (4)(3)で生成したリクエスト/レスポンスオブジェクトをサーブレットへ参照渡しする。 (5)サーブレットが処理を実行する (6)レスポンスを生成し、クライアントへ返す。 という流れかと思いますが、この際に(3)で生成されるラッパーオブジェクトや、ロードされたサーブレットが解放されるのは、レスポンスを返した後なのでしょうか。それとも次のリクエストに備え、オブジェクト本体は確保されたまま、次のマッピングに備えるのでしょうか。(サーブレットの解放はコンテナが終了した際?) はたまた、やはりJava特有のガベージコレクションが働き、メモリ解放はガベージコレクションのタイミングで行われるのでしょうか、、 よろしくお願い致します。。m(._.)m

    • ベストアンサー
    • Java
  • MySQLで格納されたデータを取得したい!

    MySQLで格納されたデータを取得した際に メンバを取得するにはどうしたらいいですか? 御存じの方、教えて下さい!お願いします! MySQL ------------------------------- 食品 | 材料 | 数量 | ------------------------------- 食品(1) | 材料(1) | 数量(1) ------------------------------ 食品(2) | 材料(2) | 数量(2) ----------------------------- 上記のようにでーたベースに格納してる場合に 数量(2)を知りたい場合はどのようにするのでしょうか? 取得でできた(数量(2))を構造体に格納したいのです。 現在は、mysql_query(host,"select ~"); して、mysql_store_result(); してサーバからデータを抽出した状態で 参照したい行の何列目かを知りたい場合の方法がどうしたらいいのかわかりません。 ちなみに mysql_fetch_row()を使用する場合だったら ポインタのポインタって考えればよいのですか? よろしく御教授お願いいたします!

  • C++ 多態とstlのコンテナについて

    以下のように、継承関係を作ります。 --------------------------------------- #include <iostream> #include <list> #include <vector> using namespace std; struct Base { virtual ~Base() = 0; }; Base::~Base() {} struct Sub1 : Base { int v; Sub1(int i) { v = i; } }; struct Sub2 : Base { double v; Sub2(double d) { v = d; } }; --------------------------------------- この場合、 Sub1, Sub2 のインスタンスをなにかコンテナに入れたい場合は、一般的には以下のように書けばいいのでしょうか? ---------------------- list<Base*> l; vector<Base*> v; Sub1 s1(3); Sub2 s2(4.4); l.push_back(&s1); l.push_back(&s2); v.push_back(&s1); v.push_back(&s2); ---------------------- list<Base>, vector<Base>も試しましたが list<Base> は宣言したところで vector<Base> は push_back() したところで コンパイルエラーになりました。 これは、こういうものなのでしょうか? むしろ、struct(もしくはclass)の書き方を変えたりすれば、問題なくなったりするのでしょうか? 全体としては、C++は参照などあって、どいう場合にポインタ使うべきなのかそういう部分に混乱しているような気もします。 いろいろ質問してしまって、申し分けないですがなにか ひとつでも答えられるものがあれば回答してもらえると ありがたいです。

  • 関数で値渡しと参照渡しではどっちがメモリを使うのか

    クラスAの大きなサイズのオブジェクトを、 クラスBで処理するメソッドを書こうとしています。 ◆質問 このとき、クラスBでは、byval で記載するのと、byrefで記載するのでは、 どちらの方がメモリを食わないのでしょうか? ◆自分の想定 (1)byrefで記載した場合、そのオブジェクトのポインタを受け取って処理するため、あんまりメモリは食わない。 (2)byvalで記載した場合、ある意味、.clone のような処理がされて、渡されたオブジェクトと同じサイズのメモリを食う? ※処理しようとしていることは、特に参照渡しされた変数の値を修正するような類ではないです。 なので、「オブジェクトを不用意にいじってしまう危険性」などの観点は無視し、メモリの観点の話です。 ちなみに、メソッドを、shareで宣言しようが、インスタンス化してからじゃないと使えないように宣言しようが、その関数のために使用されるメモリのサイズ(※クラスBのインスタンス化のためのメモリではないという意味)は変わらないということで合っていますでしょうか? .

  • クラスの練習をしています。

    ある方から、「参照(もしくはポインタ)を使って、人オブジェクトがまるで建物オブジェクトAから建物オブジェクトBに移動したようにしなさい」と言うお題を頂きました。 「生き霊」がなんちゃらとも言ってたのですが、 私は、人クラスを例えばmainでインスタンス化して、その実体をコピーさせて建物クラスAと建物クラスBにそれぞれ置き、それらを同期させてみてはと考えたのです。 初心者なので説明が難解してると思いますが、もし意図しているものが汲み取れた方がいらっしゃったら、 クラスの参照(もしくはポインタ)の扱い方(?)を教えてください。

  • VB2008:プロジェクト参照で名前空間が出てこない。

    VB2008:プロジェクト参照で名前空間が出てこない。 クラスライブラリを作ろうとプロジェクトC(ルート名前空間R)を作成しました。 別のプロジェクトAからCを参照しても、インテリセンスでR名前空間が出てきません。ビルドしてもダメでした。 オブジェクトブラウザにはRが表示されています。 プロジェクトCをビルドして、プロジェクトAからDLLを参照すれば問題は発生しません。 クラスライブラリも合わせて修正したいので、プロジェクト参照を使いたいのですが どのようにすれば良いのでしょうか? よろしくお願いします。

  • ダブルポインタの参照方法について

    いつも参考にさせていただいております。 C++初心者です。初歩的なことかとは思いますが、ご教授願います。 ポインタリストを引数にもつメソッドを作成しています。 この時にリストからイテレータを取り出しているのですが、ポインタからさらにポインタを 取り出しているのでダブルポインタ?になるみたいなのですが、取り出したクラスのメンバ関数の 参照方法がわかりません。->で参照するとビルドした時にコンパイルエラーが発生します。 基本的なことだとは思いますが、ご教授お願い致します。 下記サンプルコード class test { public: test(void); virtual ~test(void); TCHAR* WINAPI GetName(); void WINAPI SetName(const TCHAR* value); } BOOL WINAPI test::test(list<test *> testlist) { list<test *>::iterator itTest = testlist.begin(); while(itTest != searchCondition.end()) { itTest ← ここでGetNameを参照したい } }

専門家に質問してみよう