- ベストアンサー
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();
- みんなの回答 (8)
- 専門家の回答
質問者が選んだベストアンサー
僕ならこうする。 template<typename OutputIterator> OutputIterator test(OutputIterator out) { for (int i = 0; i < 1000; i++){ *out++ = A(i); } return out; }
その他の回答 (7)
- επιστημη(@episteme)
- ベストアンサー率46% (546/1184)
>template<typename OutputIterator> >>OutputIterator test4(OutputIterator out) { >> for (int i = 0; i < 1000; i++){ >> *out++ = Sample(i); >> } >> return out; >>} > > コンパイルは通りましたが、テンプレートのことがわからず > どう呼び出せば(利用すれば)よいのでしょうか? std::vector<Sample> v; test(std::back_inserter(v)); // 要 #include <iterator>
- jacta
- ベストアンサー率26% (845/3158)
> auto_ptr<vector<Sample>> ではなく、auto_ptr<vector<Sample> >です。 最後の > の前には、必ず一つ以上の空白類文字を入れてください。そうしないと、コンパイラは >> (右シフト演算子)だと勘違いします。
- koyadi
- ベストアンサー率36% (7/19)
No4です。 jactaさんのコードではauto_ptrを使っているので オブジェクトの破棄の心配をする必要はありませんでしたね。 失礼しました。
お礼
サンプルで、コピーコンストラクタとデストラクタが頻繁に呼ばれ非効率なのがわかりました。 push_backの引数?でコピーコンストラクタが呼ばれ、 push_backが実行される?とデストラクタが呼ばれる 悲惨なものでした。 あと、auto_ptrを使ってコンパイルしたのですが、以下のエラーが発生しました。 error C2146: 構文エラー : ',' が、識別子 'test3' の前に必要です。 error C2065: 'test3' : 定義されていない識別子です。 error C2144: 構文エラー : ')' が型 'void' の前に必要です。 error C2143: 構文エラー : ';' が '{' の前に必要です。 error C2143: 構文エラー : ')' が ';' の前に必要です。 error C2059: 構文エラー : ')' error C2143: 構文エラー : ';' が '{' の前に必要です。 error C2143: 構文エラー : ';' が '}' の前に必要です。 error C2143: 構文エラー : ';' が '}' の前に必要です。 error C2143: 構文エラー : ';' が '{' の前に必要です。 ★そのソースです。 #include <memory> using namespace std; ...略 auto_ptr<vector<Sample>> test3(void){ auto_ptr<vector<Sample> > ret(new vector<Sample>); for (int i = 1; i <= 5; i++) { ret->push_back(Sample(i)); } return result; }
- koyadi
- ベストアンサー率36% (7/19)
jactaさんのコード(test2関数)とtobasuさんのコード(test関数)にログを出すようにしてみましたので実行してみてコンストラクタ、コピーコンストラクタ、デストラクタ がどのように呼ばれるかを確認してみるとご自分のコードの効率の悪さがわかると思います。 main内でtest、test2だけを実行できるようもう一方をコメントアウトしてコンパイル後実行してみてください。 またjactaさんのコードの場合オブジェクトの破棄を利用者側が行わないとメモリーリークを起こします。(デストラクタがよばれなくなることからわかると思います) class Sample { public: Sample( ); Sample( int i ); Sample(const Sample& rVal); virtual ~Sample(); int GetMem( void ){return mem;} private: int mem; }; Sample::Sample():mem(0) { } Sample::Sample( const Sample& rVal ):mem(rVal.mem) { cout << "Copy Constructor mem = " << mem << endl; } Sample::Sample( int i ):mem(i) { cout << "Constructor i = " << i << endl; } Sample::~Sample() { cout << "Dstructor " << mem << endl; } vector<Sample> test(void) { vector<Sample> ret; for( int i = 1 ; i <=5 ; i++ ) { cout << "loop cnt = " << i << endl; Sample a(i); ret.push_back( a ); } return ret; } vector<Sample*> test2(void) { vector<Sample*> ret; for( int i = 1 ; i <=5 ; i++ ) { cout << "loop cnt = " << i << endl; Sample* a = new Sample(i); ret.push_back( a ); } return ret; } int main(int argc, char* argv[]) { // test関数のテスト start //vector<Sample> val = test(); //cout << "test called" << endl; // test関数のテスト end // test2関数のテスト start vector<Sample*> val2 = test2(); cout << "test2 called" << endl; vector<Sample*>::iterator beg = val2.begin(); vector<Sample*>::iterator end = val2.end(); for( ; beg != end ; beg++ ) { cout << "val2 = " << (*beg)->GetMem() << endl; } //オブジェクトの破棄 beg = val2.begin(); for( ; beg != end ; beg++ ) { delete (*beg); } //オブジェクトの破棄終了 // test2関数のテスト end return 0; }
- jacta
- ベストアンサー率26% (845/3158)
> 副作用とはどういうものでしょうか? 返却値を生成する以外の作用はすべて副作用です。 具体的には、ファイルに出力するとか、OS等の状態を遷移させるとか、静的なオブジェクトを更新するとかです。
- jacta
- ベストアンサー率26% (845/3158)
#1です。 すみません。new式を忘れていました。 誤) auto_ptr<vector<A> > result; 正) auto_ptr<vector<A> > result(new vector<A>); です。
- jacta
- ベストアンサー率26% (845/3158)
効率の良さという観点では、格納用のvectorを参照かポインタで渡すのが一番だと思います。 ただ、今回例に挙げられているtest関数のような、副作用のないものであればよいのですが、副作用がある場合には、例外安全も一緒に考えないといけません。 具体的には、 void test(vector<A>* p) { vector<A> temp; for (int i = 0; i < 1000; i++) temp.push_back(A(i)); p->swap(temp); } とするか、 auto_ptr<vector<A> > test() { auto_ptr<vector<A> > result; for (int i = 0; i < 1000; i++) result->push_back(A(i)); return result; } あたりが妥当ではないでしょうか。
お礼
ご回答ありがとうございます。 >副作用のないものであればよいのですが 副作用とはどういうものでしょうか?
お礼
回答ありがとうございます。 > >template<typename OutputIterator> >OutputIterator test4(OutputIterator out) { > for (int i = 0; i < 1000; i++){ > *out++ = Sample(i); > } > return out; >} コンパイルは通りましたが、テンプレートのことがわからず どう呼び出せば(利用すれば)よいのでしょうか? *out++部分で悩んでいます。 ++演算子を定義?する必要があるのでしょうか?