ちょっと長文です。下のほうに質問があります。
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;
}
ご回答ありがとうございます。
頂いたソースですが、
Borland C++ Compiler 5.5でも、codepadのおそらくgccでも
コンパイルエラーが出てしまいました。。
Microsoft Visual Studio 2005でならコンパイルできましたが、
現時点の自分の読み取り能力ではちょっと解読できませんでした><
どのような場合に生のポインタを用いたコンテナを使ったときに
問題になるのかをもう一度整理してみようと思います。
また参照カウント式のスマートポインタを使ったときに、
内部がどのような動きになるのかについても考えてみます。
その上でどうしても今作ろうとしているものに参照カウント式の
スマートポインタを使ったほうがよいのかを判断しようと思います。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- 賃貸マンション・賃貸アパート 周囲に気づかれずアパートもしくは貸しコンテナを借りる方法 1 2022/07/31 18:18
- C言語・C++・C# 関数ポインタの高速化のメリット 7 2023/05/05 20:15
- その他(行事・イベント) パーティーのチケット販売・返金について 1 2022/07/21 22:43
- Excel(エクセル) Excel 表の作成について 3 2022/06/16 12:15
- レシピ・食事 コンテナ船のコンテナはどんなルールに従って乗せているのですか? 3 2022/06/17 10:50
- 掃除・片付け 段ボールに代わる収納ボックスについて 1 2022/03/27 02:23
- フリーソフト 色々な形式の個人情報を後で参照しやすいようWindow10で管理したいのですが、どんな方法があるの? 1 2023/04/29 16:46
- DIY・エクステリア 製罐の部品について 1 2023/02/27 19:03
- ピクニック・キャンプ ルーフラックについて皆様の話を聞きたくて投稿しました。ラングラーに乗っていましてルーフラックを購入し 3 2023/04/26 17:07
- その他(社会・学校・職場) 業務内容についてどう思いますか? 私は客先の仕事を下請けとして行うという仕事をしていますが、(客先の 2 2022/05/04 16:17
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
int main()、void main()、void...
-
【gcc・cygwin】multiple defin...
-
Notepad++の関数リスト表示の変...
-
静的でないメンバ関数の呼び出...
-
多重定義が起きている?--lnk20...
-
C# Controls.Addで動的に配置し...
-
ArduinoでMouse関数を使用して...
-
【VC++6.0】イベントハンドラ関...
-
C++にてtemplateで受け取った任...
-
ウインドウの移動禁止
-
_beginthreadにて発生するコン...
-
VC++でGetKeyboardStateがうま...
-
メッセージマップ(ON_CONTROL_...
-
void main()って誰が最初?:AN...
-
critical error c0000005
-
コールバックって・・・
-
gcc: incompatible pointer type
-
const_castのつかいどころを教...
-
SC_SIZEがわからない
-
既定のコンストラクタがありま...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
Notepad++の関数リスト表示の変...
-
ArduinoでMouse関数を使用して...
-
【gcc・cygwin】multiple defin...
-
戻り値を返す関数の前に(void)...
-
多重定義が起きている?--lnk20...
-
C++にてtemplateで受け取った任...
-
既定のコンストラクタがありま...
-
静的でないメンバ関数の呼び出...
-
gcc: incompatible pointer type
-
C# Controls.Addで動的に配置し...
-
int main()、void main()、void...
-
(void)0 はどんな意味ですか
-
VC++でGetKeyboardStateがうま...
-
void*型の配列について
-
C# KeyDownイベントでショート...
-
const_castのつかいどころを教...
-
H8マイコンのシリアル通信につ...
-
コールバックって・・・
-
関数ポインタについて
-
void main()って誰が最初?:AN...
おすすめ情報