クラスとSTLコンテナの組み合わせについて

このQ&Aのポイント
  • C++のSTLコンテナを使用する際に、クラスオブジェクトを直接挿入・削除するとパフォーマンスに影響が出ることがあります
  • 大きなリソースを持つオブジェクトをコンテナに入れる場合は、オブジェクトのコピーが負荷になる可能性があります
  • クラスオブジェクトをポインタでコンテナに入れる場合は、デストラクタが呼ばれないため注意が必要です
回答を見る
  • ベストアンサー

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

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

質問者が選んだベストアンサー

  • ベストアンサー
  • qwertfk
  • ベストアンサー率67% (55/81)
回答No.3

コンテナということですので、shared_ptrよりはptr_containerではないでしょうか。 ptr_vectorとか。

kuramiya
質問者

お礼

コンテナ専用のポインタのラッパーがあったんですね さながら、値コンテナを参照コンテナっぽく使うためのものでしょうか? 調べてみて、使ってみようと思います

その他の回答 (2)

回答No.2

キホン値コンテナですからねー。 C++11なら push_back を emplace_back にとっかえれば 無駄なコピーが減りますけども。

kuramiya
質問者

お礼

値コンテナという呼び方があるのですか JavaやC#のようなガベージコレクタありの言語で実装されているコンテナ(コレクション)は参照コンテナだったんですね C++11での新しい情報に関して、ありがとうございます

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.1

STL のコンテナは値ベースですから, はっきり言ってどうしようもないですね. 簡単に済ますなら shared_ptr がベストではないかと.

kuramiya
質問者

お礼

なるほど 回答ありがとうございます

関連するQ&A

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

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

  • STLについて

    VC++6を使っています。ベクタを戻り値とするプログラムを書いています。効率が悪く感じるのですが、STL?ではこういうやり方は正しいのでしょうか? また、一般的にSTLで引数や戻り値を扱う場合、どのようなタイプ(string?)を使えば、効率よく、きれいなプログラムが書けるのでしょうか? class A{ ... } vector<A> test(void){ vector<A> ret; for (int i = 0; i < 1000; i++){ ret.push_back( A(i) ); } return ret; } vector<A> a = test(); // 巨大なコンテナが返され、aにコピーされる? ※基本的に戻り値の仕組みが理解不足です。 char *の場合は、char配列のポインタが返され、新たな変数にポインタ値がコピーされるという解釈で結構ですか? char * sample(void){ char *p = new [1000]; return p; } char *q = sample();

  • shared_ptrからpimplのデストラクタ呼び出し

    pimplイディオムの勉強をするために以下のようなプログラムを作りました。 //MySharedPtr.h template<typename tnT> class MySharedPtr {  tnT *mPtr; public:  MySharedPtr(tnT *ptr) : mPtr(ptr) {}  ~MySharedPtr() { delete mPtr; } //(1) }; //Foo.h class Foo {  struct stImpl;  MySharedPtr<stImpl> mImpl; //(2) public:  Foo(); }; //Foo.cpp Foo::stImpl {  ~stImpl() { cout << "xxx" << endl; } //(3) }; Foo::Foo() : mImpl(new stImpl) {} //main.cpp int main() {  Foo foo; } これをコンパイルすると、(1)の所でtnTのデストラクタが見つからない旨のワーニングが出て、mainを実行するとstImplのデストラクタが呼ばれずに(3)の出力は出ません。ただ、(2)をboost::shard_ptrに変えるとワーニングも出ないし(3)の出力もされます。(2)の箇所でstImplが宣言だけなのは両者とも同じだと思うのですが、なぜboostはワーニングが出ないのでしょうか。また、MySharedPtrでもワーニングを出さないようにすることはできるのでしょうか。もちろん、スマートポインタを実装するよりもboostを使用した方が良いとは思うのですが、何でboostはうまくいくのか不思議に思い、質問させていただきました。

  • クラスの合成ができない

    大学で数値計算をしており、Matrixクラスを作ったのですが他のクラスや構造体のメンバ変数に取り入れようとしてもできません。 以下のようなコードなのですがどうしてできないのでしょう? #include<iostream> using namespace std; class Matrix{ private: double **ptr; int Row,Col; public: Matrix(int i=1, int j=1);/* コンストラクタ */ Matrix(const Matrix &);/* コピーコンストラクタ */ ~Matrix();/* デストラクタ */ }; Matrix::Matrix(int Dim1,int Dim2) { Row=Dim1; Col=Dim2; for(int i=0;i<=Dim1;i++){ ptr[i]=(double*) new double[Dim2+1]; if(ptr[i]==NULL){ cerr<<"Memory Allocation Error.\n"; abort(); } } } Matrix::~Matrix() { for(int i=1;i<=Row;i++)delete [] ptr[i]; delete [] ptr; ptr=NULL; } struct Test{ Matrix A(3,3);//これはエラー }; int main() { Matrix B(3,3);//これは出来た return 0; }

  • C++のクラスについて

    /*以下のコメントがある行では何故、コンストラクタ(class2::class2)を指定出来ないのですか? デストラクタ(class2::~class2)の場合も問題なくコンパイルが通り、実行できます (http://codepad.org/1oJkxjyZ の23行目) 開発環境 Windows XP SP3 コンパイラ:GCC 実行結果 class1のコンストラクタ class2のコンストラクタ aiueoの実行 class2のデストラクタ class1のデストラクタ */ #include<iostream> class class1; class class2; class class1{ public: class1(); ~class1(); private: class2*pointer; }; class class2{ public: class2(); ~class2(); void aiueo(); }; class1::class1(){ std::cout<<"class1のコンストラクタ"<<std::endl; pointer=new class2(); pointer->aiueo(); //aiueoを~class2に置き換えてもコンパイル出来るが、class2だとエラーが出る } class1::~class1(){ delete pointer; std::cout<<"class1のデストラクタ"<<std::endl; } class2::class2(){ std::cout<<"class2のコンストラクタ"<<std::endl; } class2::~class2(){ std::cout<<"class2のデストラクタ"<<std::endl; } void class2::aiueo(){ std::cout<<"aiueoの実行"<<std::endl; } int main(){ class1 test1; return 0; }

  • VC++.NETと標準C++とSTLの相性などの質問事項

    自己研鑽のために、標準C++を学習し、STLについても学習しました。仕事で、Javaの経験が半年以上あります。正直な感想、勉強してみると、C++のほうが、気に入ってしまいました。 マイクロソフト関連の仕事をしたことがなく、VisualBasicすらありません。最近では、C#.NETなどがでてきています。 C#2.0やjavaのJ2SE5.0ででてくるGenericや、コレクションクラスにGenericを考慮したものが でてくる。など、C++のSTLの模倣のように感じました。 C#にはデリゲートがあるようですが。関数ポインタや関数オブジェクトそのまんまに見えます。 C#2.0が気になりますがまだ、ベータ版で未来の話なので、Visul C++.NETに興味を持ちました。せっかく勉強した標準C++やSTLの知識はそこでは役に立つのでしょうか。.NETにはそちのほうで独自のstring型やコレクション型があるのではないでしょうか? .NETだと、マネージコードなどガベージコレクトがあるようです。STLのコンテナはそれぞれ内部でデストラクタがヒープの内容を廃棄してくれますが、ガベージコレクトの環境で普通にSTLを使うとどういうことになるのでしょうか? 今度、Visual C++.NETの学習をはじめるかどうかの判断材料にしたいので、現時点までの知識が有効活用できるかどうかを知りたいです。宜しくお願いいたします。

  • スマートポインタの使い方

    boost::shared_ptrについてなのですが vector<shared_ptr<CTest>> vec; 上記のベクタの要素を別のクラスからも参照しておきたい場合、 shared_ptr<CTest> p = vec[0]みたいにスマートポインタで持っておくか、 単にCTest* p = vec[0]._Ptrとしてポインタを持っておくのとどちらが良いのでしょうか?

  • C++でのクラスオブジェクトの破棄

    こんにちは。 C++では、プログラムの終了時に、全てのクラスオブジェクトは、デストラクタが呼び出されて破棄されますが、プログラムの途中で、クラスオブジェクトを明示的に破棄する方法はあるのでしょうか? 例えば、new演算子によってメモリを動的に割り当てたポインタなら、delete演算子で破棄できますが、 クラスオブジェクトにdelete演算子は使えないようです。 何かいい方法を知っておられる方がいらっしゃれば、是非アドバイスを頂きたいと思います。

  • thisをshared_ptrにキャストするには?

    こんにちは。 boost::shared_ptrを使用しているのですが、 boost::shared_ptr< Foo > lpRet ; lpRet = boost::shared_dynamic_cast< Foo, Hoge >( this ) ; のようなthisポインタをキャストしたいのですが、 どのように書けばよろしいのでしょうか?

  • STLを使わずに可変長配列を再現する方法

    STLのlistが(配列に比べると)想像以上に遅かったので C++で可変長配列を再現したいのですけども 配列の拡張が思った以上に遅く困っています。 毎回newではオーバーヘッドが発生しますので、 現在は配列を一定数確保しておき 足りなくなったら配列を拡張(再確保)しています。 現在の配列のアドレスを一旦退避させてdeleteし、 新たにnewで生成して復帰させるといった感じです。 ただしこれでは、配列の要素数が増えるほど遅くなり、 オブジェクトの参照ならまだしも実体の場合は 全てコピーしなければならないので、 場合によってはSTLのlistよりも遅くなってしまいます。 newで生成してるのでできればreallocは使わずに 再現したいのですが、どうにか方法は無いでしょうか? よろしくおねがいします。 //----------------------------------------------- struct Test {   int val;   Test( int _val ){ val=_val; } }; Test obj1( 1 ); Test obj2( 2 ); Test obj3( 3 ); // 元のデータに代入 Test **ptr = new Test*[2]; ptr[0] = &obj1; ptr[1] = &obj2; // 退避させる Test **tmp = new Test*[2]; for( int i=0; i<2; i++ ) tmp[i] = ptr[i]; // 拡張する delete [] ptr; ptr = new Test*[4]; // 復帰させる for( int i=0; i<2; i++ ) ptr[i] = tmp[i]; delete [] tmp; ptr[2] = &obj3; //----------------------------------------------- ※NULLチェックなどはここでは省いています。