• ベストアンサー

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();

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

  • ベストアンサー
回答No.7

僕ならこうする。 template<typename OutputIterator> OutputIterator test(OutputIterator out) {  for (int i = 0; i < 1000; i++){   *out++ = A(i);  }  return out; }

tobasu
質問者

お礼

回答ありがとうございます。 > >template<typename OutputIterator> >OutputIterator test4(OutputIterator out) { > for (int i = 0; i < 1000; i++){ > *out++ = Sample(i); > } > return out; >} コンパイルは通りましたが、テンプレートのことがわからず どう呼び出せば(利用すれば)よいのでしょうか? *out++部分で悩んでいます。 ++演算子を定義?する必要があるのでしょうか?

その他の回答 (7)

回答No.8

>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)
回答No.6

> auto_ptr<vector<Sample>> ではなく、auto_ptr<vector<Sample> >です。 最後の > の前には、必ず一つ以上の空白類文字を入れてください。そうしないと、コンパイラは >> (右シフト演算子)だと勘違いします。

  • koyadi
  • ベストアンサー率36% (7/19)
回答No.5

No4です。 jactaさんのコードではauto_ptrを使っているので オブジェクトの破棄の心配をする必要はありませんでしたね。 失礼しました。

tobasu
質問者

お礼

サンプルで、コピーコンストラクタとデストラクタが頻繁に呼ばれ非効率なのがわかりました。 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)
回答No.4

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)
回答No.3

> 副作用とはどういうものでしょうか? 返却値を生成する以外の作用はすべて副作用です。 具体的には、ファイルに出力するとか、OS等の状態を遷移させるとか、静的なオブジェクトを更新するとかです。

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.2

#1です。 すみません。new式を忘れていました。 誤) auto_ptr<vector<A> > result; 正) auto_ptr<vector<A> > result(new vector<A>); です。

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.1

効率の良さという観点では、格納用の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; } あたりが妥当ではないでしょうか。

tobasu
質問者

お礼

ご回答ありがとうございます。 >副作用のないものであればよいのですが 副作用とはどういうものでしょうか?

関連するQ&A

  • VectorなどSTL?テンプレートの使い方

    戻り値がポインタの場合、関数から抜け出すと値の保証が無いので、それを使用する場合は、変数にコピーして使うと値は残る(アクセス可能)と理解しています。 char tmp[128]; strcpy(tmp, test()); それで、次のような vector??を使った場合、表示の場合は問題ないかもしれませんが、その後、値を使い続ける場合、ポインタのままでよいのか疑問に思っています。 以下のソースは勝手気ままに記述したものですが、 VC++6でエラーなく動作(とりあえず動く)しているのですが、今後発生する問題など知りたいです。 #include "stdafx.h" #include <string> #include <iostream> #include <vector> #include <sstream> using namespace std; class A { string str; vector<A *> v_cls; public: A(){ } // デフォルトコンストラクタが必要? A(string s){ str = s; } void PrintData(void){ // 表示 cout << str << endl; } // 1から9までの[0]-[9]の文字列を作成 vector<A *> ArraySet(void){ stringstream ss; for (int i=0; i < 10; i++){ ss.str(""); ss << "function [" << i << "]\n"; v_cls.push_back( new A( ss.str() ) ); } return v_cls; } }; void main(void){ // 1から9までの[0]-[9]の文字列を作成 // これは問題ないと思う vector<A *> v; stringstream ss; for (int i=0; i < 10; i++){ ss.str(""); ss << "[" << i << "]\n"; v.push_back( new A( ss.str() ) ); } v[1]->PrintData(); v[3]->PrintData(); ////cout << v.size(); // クラス自身にvector配列?を返す処理 // とりあえず動いているだけ??? A x; vector<A *> ret = x.ArraySet(); // このような代入でも問題ないのでしょうか? ret[5]->PrintData(); // 表示だけなので、問題なし? ret[0]->PrintData(); // vやret, xの解放仕方とタイミングはどうすればよいのでしょうか? }

  • C++ STL vectorの使い方

    こんばんは。 C++のstd::vectorに関する質問です。 vectorをポインタ渡しにしたときに メンバにアクセスする方法を知りたいのですが・・・ 以下ソースの☆の部分をどう記述したらよいでしょう? #include <vector> typedef struct test {  char name[10];  char id[2]; } TEST; void funcVectorTest( std::vector<TEST> *a); int main(){  std::vector<TEST> a;  int i;  TEST foo= {"Taro","0"};  a.push_back(foo);  printf("%s",a[0].name);  a.push_back(foo);  printf("%s",a[1].name);  funcVectorTest(&a);//vectorのアドレス渡しテスト  printf("%s", a[2].name);//vectorのアドレス渡し確認  return 0; } void funcVectorTest( std::vector<TEST> *a) {  int i;  int cnt;  TEST *b;  b = new TEST[3];  TEST foo= {"Taro","0"};  a->push_back(foo);  cnt = a->size();  for( i = 0; i < cnt;i++){  //以下でa[i]のnameにアクセスしたいのですがうまくいっていません。  //☆strcpy( b[i].name, a[i]->name );  }  delete[] b; } お分かりになる方、お知恵をお貸し下さい(><) vectorについて最近知ったばかりでいまいち使い方が 分かっていない部分があるので このやり方がまずいということであれば教えていただけると 助かります。 よろしくお願いしますm( _ _ )m

  • char*の実体の数値をchar変数に格納する方法

    ある関数の戻り値がchar*でその関数の戻り値をchar変数に格納したいです。 char *ret_ch() { char *p="12"; return p; } int main(){ char res; //ここでret_ch()の戻り値の実体数値を代入 res=*ret_ch(); cout<<"RET=="<<ret<<endl; return 0; } char型は1バイトなので一文字しか入りません。 char型に数値として扱い、上記のポインターの 実体数値を格納するにはどのようにしたらいいのでしょうか? よろしくお願い致します。

  • STLで、vectorのファイルへの書き出し、読み込み。

    STLで、vectorのファイルへの書き出し、読み込み。 C++ の STL で vector をファイルに書き出し、読み込もうとしておりまして、まずは書き出しで躓いております。 vector<int> testvector; for (i = 0 ; i < 10 ; i++) testvector.push_back( i ); ofstream out("test.dat", ios::out | ios::binary); if (!out) return 1; out.write((vector<int>) testvector, sizeof(testvector)); out.close(); こんな感じのコードですと、 error: no matching function for call to ‘std::basic_ofstream<char, std::char_traits<char> >::write(std::vector<int, std::allocator<int> >, long unsigned int)’ /usr/include/c++/4.2.1/bits/ostream.tcc:173: note: candidates are: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::write(const _CharT*, std::streamsize) [with _CharT = char, _Traits = std::char_traits<char>] とのことです orz. どのようにすれば vector を書き出し、そして読み込むことができるのでしょうか。情報がありましたら是非お寄せください。

  • returnと条件式内の代入

    Cでmemcmpライクな関数が必要になり作りました。(正確には中でmemcmpを何回か呼び出して比較をする関数) そのときに出た疑問なのですが、ループ内でif文→returnとするのと、ループの条件にif文の条件を織り込んで、関数の最後でreturnするのとどちらが良いのか。 作った後で、いくつかのサイトでreturnはまとめるほうがいいとありましたので2つめの関数も考えました。しかし、条件式に=(代入)を書くのは好ましくないとする考えもあるようで、もう一つ作りました。しかし、初期化直後のretを比較するのは気分が悪いのです。悩んでいます。つまり、次のような関数でより好ましいのはどれでしょうか? (いずれも質問用にmemcmpに書き直してます) int mymemcmp(const void *a, const void *b, size_t cnt) {   const unsigned char *ap = a, *bp = b;   int i, ret;   for (i=0; i<cnt; i++)   {     ret = ap[i] - bp[i];     if (ret != 0)     {       return ret;     }   }   return 0; } int mymemcmp(const void *a, const void *b, size_t cnt) {   const unsigned char *ap = a, *bp = b;   int i, ret=0;   for (i=0; i<cnt && (ret = ap[i] - bp[i]) == 0; i++)     ;   return ret; } int mymemcmp(const void *a, const void *b, size_t cnt) {   const unsigned char *ap = a, *bp = b;   int i, ret=0;   for (i=0; ret == 0 && i<cnt; i++)   {     ret = ap[i] - bp[i];   }   return ret; }

  • C++の複数戻り値について

    質問の閲覧ありがとうございます。 C++をはじめたばかりで勉強中のみなのですが どうしてもうまくいかない壁にぶつかってしまったので 是非お力を貸していただきたく、質問させていただきました。 C++にて課題を出されていまして、それを実現するのに ある関数に対し引数を複数渡し、戻り値を複数得たいのですが 下記のようなコードで、(実際は戻り値、引数がもっと多くなる 想定なのでreturnでは足りないです) 単純に、mainのa2の引数を"参照渡し"としtestにて代入した文字列を mainで再度受け取る、といったことを試しているのですが、うまくいかず このような形では実現不可能なのでしょうか? (文字列の代入をstrcpyに、charの宣言時に要素数を指定したりせずに) #include<iostream> using namespace std; void test(char* a2); int main() { char a2; test(&a2); cout << a2 << endl; } void test(char* a2) { a2="TEST_MESSEAGE1"; } 素人丸出しな内容で申し訳ないですが、ネット上の色々なサンプル等 で試してみても、理解がうまく得られませんでした。。。 ポインタ等の理解が浅いのもあるのかと思いますが。 ぜひご教授よろしくお願いいたします。

  • 文字列の受け渡し

    先ほど質問したものですが、お願いします。 関数で戻り値として、文字列を扱う場合、 char* sendstr(void){ char* mychar="HELLO!!\n"; return mychar; } ならうまくいきますが、 char* sendstr(void){ char mychar[]="HELLO!!\n"; return mychar; } だと、うまくいきません。 配列の場合、mycharで、ポインタと なると、思うのですが。 後者の方が、分かりやすそうですが、 だめなのでしょうか。 (char*は文字型のポインタで、文字列 へのポインタになるのでしょうか)。

  • ポインタを使って構造体の配列を戻り値にするには

    関数の戻り値を構造体の配列(アドレスを受け渡しを利用して)にしたいのですがうまくゆきません。 以下のプログラムではコンパイルはできるのですが、 a0 = 2 a1 = 4198512 a2 = 4329332 と表示されてしまいa1,a2がうまくゆきません。 ********************************************* #include<stdio.h> struct test{ int a; }; struct test *func(void); void main(void) { struct test *data;//構造体ポインタ int i; data = func(); //ポインタにtest関数の戻り値(アドレス)を代入 for(i=0;i<=2;i++){   printf("a%d = %d\n",i,(data+i)->a); //構造体要素を表示 } } struct test *func(void) { struct test data[3]={1,2,3}; //構造体配列を定義 return (&data[0]); //構造体配列の先頭アドレスを返す } ************************************************* test関数から受ける取ったアドレス(&data[0])をポインタ(data)に代入して1づつずらして表示させれば a0=1,a1=2,a=3 となると思ったのですがどこが間違っているのでしょうか? よろしくお願いします。

  • 配列とポインタを使って特定の文字だけ大文字にする

    配列とポインタを使って特定の文字だけ大文字にするプログラムを作りたいのですがどのように作ればいいのでしょうか? 例えば、sportsのsだけ判別してSportSというふうにしたいです。 一応以下のようなプログラムを作ったのですが、実行してもsportsのままで何も変わりません・・・。 #include<stdio.h> void mojihenkan(char *); main(void) { char moji[8]={"sports"}; char *p; int i; mojihenkan(moji); p=moji; for(i=0;i<8;i++){ printf("%c",*(p+i)); } return 0; } void mojihenkan(char *a) { int i; for(i=0;i<8;i++){ if(*(a+i)=='s'){ a-32; } } }

  • ポインタ配列

    "one","two","three","four","five","six","seven","eight","nine","ten" のポインタ配列の文字列を、ASCIIコード順に並べ変えようと思ったのですが、 もうどこが間違っているかさえわからないぐらいになってしまいました。 まだまだはじめたばかりなもので、わからないことだらけなんで、 できるだけわかりやすい説明おねがいします。 関数の引数に問題があるのじゃないかと思ったのですが、 何かいいアドバイスありましたら、お願いします。 #include <stdio.h> /* 関数のプロトタイプ宣言 */ int strmp(char *,char *); void cpy(char *,char *); int main (void) { /* ポインタ配列の定義 */ char *x[10]={"oneee","twooo","three","fourr","fivee","sixxx","seven","eight","ninee","tennn"}; /* ポインタのポインタの定義 */ char **pp=x; char k[100]; char *p=k; int i,t,a,b,c,d; a=0; /* ポインタ配列を自作関数を使って、ASCIIコードの大きいほうからに並び替える */ for(i=0;i<9;i++) { for(t=1;t<10;t++) { a=strmp(*(pp+i),*(pp+t)); if(a<0) { cpy(p,*(pp+i) ); cpy(*(pp+i),*(pp+t) ); cpy(*(pp+t),p); } } } for(i=0;i<10;i++) { printf("%s ,",x[i]); } printf("\n"); return 0; } /* 文字の比較をする関数 */ int strmp(char *x,char *y) { int i; for(i=0;*(x+i)==*(y+i);i++) { if( *(x+i)=='\0') { return 0; } } return *(x+i)-*(y+i); } /* 文字をコピーする関数 */ void cpy(char *a,char *b) { int i; for(i=0;*(b+i)!='\0';i++) { *(a+i)=*(b+i); } *(a+i)='\0'; }

専門家に質問してみよう