• ベストアンサー

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の解放仕方とタイミングはどうすればよいのでしょうか? }

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

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

> deleteの場所が良くわかっていません。 vector<A*>オブジェクトのデストラクタが呼ばれる直前で、各要素に対してdeleteを行ってください。ただし、デストラクタが呼ばれるところであればどこでもdeleteすればよいというものではなく、本当に要素を解体したいところでのみ行う必要があります。 ポインタを要素に持つコンテナは、このように所有権が不明瞭になります。特定の関数の中だけで使う局所的なオブジェクトや、クラスのメンバ関数からしか操作しないデータメンバの場合はまだよいのですが、関数の引数や返却値に使うのは、あまりよい設計とはいえません。 > 例外処理は自身ないのですが、ソースが長いと聞きたい焦点がぼけると思いまったく書きませんでした。 今後発生する問題を知りたいとのことですので、例外処理は省略すべきではありません。

tobasu
質問者

お礼

ポインタを要素に持つコンテナを改め、以下のように変更しました。 これで問題ないと思いますが、突っ込み所があれば、ご指摘お願いします。 ※コンテナ?とイテレータ?でポインタを使わない場合は、勝手に解放してくれるのでしょうか? #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; } ~A(){} // 表示 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 << "[" << i << "]"; v_cls.push_back( A( ss.str() ) ); } return v_cls; } }; void main(void){ // 1から9までの[0]-[9]の文字列を作成 // これは問題ないと思う A x; vector<A> ret = x.ArraySet(); // この代入は問題ないのでしょうか? // この位置からの例外処理は正しいですか? try{ ret[5].PrintData(); cout << "OK 5" << endl; ret[0].PrintData(); cout << "OK 0" << endl; ret[10].PrintData(); cout << "OK 10" << endl; } catch (...) { // 一般的な例外処理の書き方がわかりません。 cerr << "例外が発生しました。" << endl; } // xはmainからぬけると、消滅解放してくれると思いますが、 // ArraySetメソッドでpush_backした分は解放しなくてもよいのでしょうか? }

その他の回答 (2)

  • asuncion
  • ベストアンサー率33% (2126/6288)
回答No.2

> strcpy(tmp, test()); これがうまくいくかどうかは、test() の実装によります。 こう書けば必ずうまくいく、というものではありません。

tobasu
質問者

補足

char *test(void){ char dmy[] = "轟々と、隼は行く";  return dmy; } これでもダメですか?

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

突っ込みどころ満載ですが、とりあえず致命的な部分だけ指摘します。 vにせよretにせよ、コンテナの要素がポインタですので、解体時には、各要素に対してdeleteを行う必要があります。(現状ではリークします) そもそも、コンテナの要素にポインタを使うのは、所有権が不明瞭になることもあり、あまりよい設計とはいえません。 もう一点、例外に対する配慮が全くなされていません。現状では、どこかで例外が発生すると、即クラッシュします。

tobasu
質問者

お礼

戻り値=関数・オブジェクトメソッドが私的に スマートだと勝手に思っているのですが、この書き方でよい設計にする場 どのようにするのでしょうか? deleteの場所が良くわかっていません。 例外処理は自身ないのですが、ソースが長いと聞きたい焦点がぼけると思いまったく書きませんでした。

関連するQ&A

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

  • 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

  • STLのvectorで・・・

    4次元配列を使いたいので以下のようなプログラムを組んでみました。 -------------------------------------------------- #pragma warning( disable : 4786 ) #include <vector> #include <iostream> using namespace std; void EditYMatrix(vector< vector< vector<int> > > *vi, int i); void EditSquareMatrix(vector< vector<int> > *vi, int i); int main(int argc, char* argv[]) { int i, j, c; vector< vector< vector< vector<int> > > > vi; cout << "Xの要素数を入力してください" << endl; cin >> c; vi.resize(c); cout << "Yの要素数を入力してください" << endl; cin >> c; for(i=0 ; i<vi.size() ; i++) EditYMatrix(&vi[i], c); cout << "Zとωの入力" << endl; for(i=0; i<vi.size() ; i++){ for(j=0; j<vi[i].size() ; j++){ cout << i << "," << j << "番目の自由度を入力してください" << endl; cin >> c; EditSquareMatrix(&vi[i][j], c); } } return 0; } void EditYMatrix(vector< vector< vector<int> > > *vi, int i) { vi->resize(i); } void EditSquareMatrix(vector< vector<int> > *vi, int i) { vi->resize(i); for(int j=0; j<i ; j++) vi[j].resize(i); } -------------------------------------------------- Y,Z,ωは可変で、Zとωは同じにするので、 ためしにこのようなプログラムを組んでみました。 ですが、実行途中でエラーが起きてしまいます。 /* verify block type */ _ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse)); という部分でエラーが起きているのですが 知識不足で、どのような内容なのかわかりません。 どなたか分かる方教えてください。 OS:Win2000 VC++6.0

  • STLのvectorの削除

    STLのvectorの削除を行う場合に vector<myclass> v; ・・・ v.erase(it); ・・・ というように削除するiteratorを渡しますが、 任意のインデックスのvectorを削除した場合は、 どのようにそのiteratorを取得するのでしょうか。 例えばv[5]を削除したのですが、 vector<myclass>::iterator it=v.begin(); for(int i=0;i<5;i++) it++; v.erase(it); というbegin()やend()からのインクリメント・デクリメントで取得するしかないのでしょうか? ご教示願います。

  • Vectorクラスの使い方

    いつもお世話になっております。 Vector vector = new Vector(); String array[] = new String[11]; vector.addElement(array) for( int i = 0; i1 < vector.size(); i++) { String str = (String)vector.get(i); System.out.println(str); } 11の配列にデータ(String)を入力し(ここでは省略)、11すべてをVectorへいれ、String型で取り出したいのですがエラーになります。 System.out.println(vector1.get(i));だと文字化けします。 アドバイスお願いします。そういったことを書いてあるサイト等ご存知でしたらお願いします。

    • ベストアンサー
    • Java
  • C++ 構造体型のvector配列でエラーがでます

    構造体のvector配列を関数に渡しています。 以下のソースコードで、3点エラーがでます どのように変更すればよいですか? #include<stdio.h> #include<stdlib.h> #include<iostream> #include <vector> using namespace std; std::vector<int> v; typedef struct fukusosu{ int a; int b; }FUKUSOSU; int sort(vector<FUKUSOSU> v[], int N){ FUKUSOSU tmp; int j; for(int i = 0 ; i < N - 1 ; i++){ j = i ; for(int k = i + 1 ; k < N ; k++){ if(v[j].a > v[k].a){j = k;}//ここのaに対して、エラーがでます } tmp = v[j];//ここのイコールに対して、エラーがでます v[j] = v[i]; v[i] = tmp;//ここのイコールに対してエラーがでます } } int main(void){ int N; // 要素数 cin >> N; vector<FUKUSOSU> v(N); for(int i = 0; i < N; ++i){ cin >> v[i].a; cin >> v[i].b; } }

  • vectorを使っていたいのですが上手くいきません

    文字列(A)から特定の文字列(B)を抽出しながらvectorにどんどん入れていくプログラムを作成しています。(文字列(B)の位置や長さはわかっているとします。) そこで、文字列(A)から、文字列(B)に相当するアドレスをvectorにどんどん入れているのですが、先pushした値が後からpushした値と全て同じ値になってしまいます。 これは、アドレス渡しが原因と分かってはいるのですが、どう書けば上手くいくかわかりません。 そこでご教授頂きたいと思っています。 自分が書いたプログラムは以下になります。 #include <string.h> #include <stdio.h> #include <stdlib.h> #include <vector> using namespace std; void main(){ char* stringA; vector<char*> result; char temp[16];//文字列Bの大きさ for(int i=0;i<file.size();i++){ strncpy(temp,&buffer[i],16); result.push_back(*temp); //次の文字列Bの位置までインデックスを移動//// while(buffer[i]!=0x0A){ i++; } i++; } }

  • CygwinでSTLの勉強をしていますが・・・

    今C++のSTLの勉強をしています。 本に載っているサンプルプログラムを打って実行しようとしたら エラーがでてしまいました。 エラーの内容はprintとtotalが見つかりませんというエラーです。 コンパイラはcygwinを使ってます。 よろしくお願いします。 /*for_each()アルゴリズム*/ #include<iostream> #include<algorithm> #include<vector> #include<functional> #include<> using namespace std; int main() { int n[]={100,200,300,400,500,600}; int size=sizeof n/sizeof(int),i; vector<int> v; for(i=0;i<size;++i) v.push_back(n[i]); for_each(v.begin(),v.end(),print<int>()); cout<<endl; cout<<(for_each(v.begin(),v.end(),total<int>())).gettotal()<<endl; return 0; }

  • テンプレート関数に関して質問です。

    テンプレート関数に関して質問です。 wstringとstringに対して、似たような処理を行いたいので、template関数を使ってうまく定義できないかと思ったのですが、例えば、 #include<string> template<class T> void hoge(T &s){ s="a"; } void main(void){ std::string str; hoge(str); } の場合、class TがwstringだとL"a"としないといけないのですが、Tによってこれを変えることは可能でしょうか? また、できれば、hogeに想定外の変数を入れられたくないので、hogeをtypedefのようなのりで、 void foo(std::string &s); void foo(std::wstring &s); と定義しておきたいのですが何か良いアイデアはないでしょうか? 当然、hogeはstaticグローバル変数のように外部からはアクセスできないようにしておきたいのです。 よろしくお願いします。

  • 2次元vectorのerase?

    1行に4つのdouble型の値が書かれているファイルを読み込み、 iを行数として1行ずつphoton[i][0]~photon[i][3]に入れる。 photon[i][0]がある条件を満たしたらphoton[i][1]~photon[i][3]の値を photon[i-1][1]~photon[i-1][3]と photon[i+1][1]~photon[i+1][3]に 分けて加算し、photon[i][0]~photon[i][3]は消す(加算後の[i+1]が[i]に来るようにしたい)という作業をしたいのですが、消し方が良く分かりません。 やり方をご存知の方、回答お願いします。 以下のやり方では消えませんでした。vector<double>(4)のほうをeraseしてないからでしょうか。 ---------- #include <iostream> #include <fstream> #include <string> #include <list> #include <vector> using namespace std; int main(){ string str; ifstream ifs("h2o.csv"); ofstream ofs("h2o.txt"); int i = 0; double sum[3] = {0}; vector< vector<double> > photon(147, vector<double>(4)); double value[4] = {0}; for(;getline(ifs,str); i++){ sscanf(str.c_str(),"%lf,%lf,%lf,%lf", &value[0], &value[1], &value[2], &value[3]); photon[i][0] = value[0]; photon[i][1] = value[1]; photon[i][2] = value[2]; photon[i][3] = value[3]; sum[0] += value[1]; sum[1] += value[2]; sum[2] += value[3]; } for(vector< vector<double> >::iterator it = photon.begin(); it != photon.end(); it++){ if( (*it)[0] > 0.1){ cout << "delete!"; it = photon.erase(it); } cout << (*it)[0] << endl; } }

専門家に質問してみよう