• ベストアンサー

newで個別に生成した配列にNULLを代入しても大丈夫か

C++にて要素数が不定の配列のクラスをnewで生成します。 このとき、newで一度に全ての配列を生成するとメモリをかなり取るので、 指定された要素番号のみを生成したいのでダブルポインタにし、 全体を生成してから個別にクラスを生成することで、 思い通りの処理ができるようになりました。 (生成する番号は0→1→2みたいな順列ではないため) しかし、ここで1つ問題が発生しました。 まずは以下にそのソースを示します。 ----------------------------- class CHOGE {   int a; public:   CHOGE(){ a=999; }   void print(){ cout<<a<<endl; } }; ----------------------------- void main(){   CHOGE **p = new CHOGE*[3];   if( p[0] != NULL ){ // ←条件を通過してしまう     cout << "ほげ~" << endl; // ←表示される     //p[0]->print(); // ←当然エラー   }   p[0] = new CHOGE();   p[0]->print(); // ←OK   delete p[0];   p[0] = NULL;   delete [] p;   p = NULL; } ----------------------------- 上記は3個の要素の配列を生成してから、 個別に0番目の要素のインスタンスを生成しています。 しかし、上記main関数の3行目では、 インスタンスはまだ生成していなにもかかわらず NULLチェックを通り過ぎてしまいます。 そこで上記main関数の2行目に  for(int i=0; i<3; i++) p[i] = NULL; という処理を入れると期待通りに動いてくれるのですが、 どうも引っかかるといいますか、何かの情報を消してしまったり やってはいけないことをやってそうで、不安なのです・・・。 上記のようなとき、NULLを代入しても大丈夫なのでしょうか?

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

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

> 上記のようなとき、NULLを代入しても大丈夫なのでしょうか? 大丈夫です。 ところで、 p[0] = new CHOGE(); または p[0]->print(); // ←OK に失敗して例外が送出された場合、このプログラムではメモリリークが発生します。 pは、newで割り付けるより、std::vectorを使うなどした方が安全です。

その他の回答 (3)

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

いや, CHOGE **p = new CHOGE*[3]; をやったあとで p[0] に入っているゴミが NULL じゃなかった, ということではないかな>#1. ここに入っていた値はただのゴミなので NULL を代入するのは問題ありません.

  • aigaion
  • ベストアンサー率47% (287/608)
回答No.3

動的確保の CHOGE **p = new CHOGE*[3]; は,静的確保にすると CHOGE *p[3]; と,同じことですね. CHOGEへのポインタを3つ含む配列が確保されていますが C++言語の場合,領域を確保するときに初期化を行わないので 配列のそれぞれの要素が何を指しているかは不定です. ポインタ自体は3つ確保されているのでそこにNULLを代入しても問題ないですよ.

  • SAYKA
  • ベストアンサー率34% (944/2776)
回答No.1

>CHOGE **p = new CHOGE*[3]; この時点で p[3] で確保されるからnullではない、というオチじゃない? 分解すると こうだよね? CHOGE **p = {CHOGE*[0],CHOGE*[1],CHOGE*[2]} よって p[0]=&(CHOGE*[0]); p[1]=&(CHOGE*[1]); p[2]=&(CHOGE*[2]); だからnullじゃないのでは・・・

関連するQ&A

  • 多次元配列の new

    多次元配列を new すると、どのような型のサイズの領域の配列が確保されるんでしょうか?たとえば、  int (*a)[2] = new int[3][2]; とすると、  1. 長さ2のintの配列へのポインタ型の長さ3の配列の領域が確保される のか、  2. int[3][2] すなわち、int が 6 つ分の領域が確保される のか。 今まで、「そりゃあ 2 の方だろう」と信じ込んであまり考えずにいたんですが、「コードの型形式からすると 1 の方の解釈でもいいよなぁ」と、ふと思ったものですから、質問させていただきました。 わたしの環境で調べてみると(配列用のハウスキーピング的な余分の領域とか、パディングなどは無視して)、確かに 1 の方なんですか、これで標準準拠なんでしょうかね?^^; XP Home Edition Ver.2002 SP2 cygwin v.1.0.2-1 GNU g++ v.4.1.1 ===== #include <iostream> #include <new> #include <cstdlib> struct A { char a; void *operator new(std::size_t s) { void *p = std::malloc(s); std::cout << "A::new(): " << p << '\t' << s << '\n'; return p; } void operator delete(void *p, std::size_t s) { std::cout << "A::delete(): " << p << '\t' << s << '\n'; if (p) std::free(p); } void *operator new[](std::size_t s) { void *p = std::malloc(s); std::cout << "A::new[](): " << p << '\t' << s << '\n'; return p; } void operator delete[](void *p, std::size_t s) { std::cout << "A::delete[](): " << p << '\t' << s << '\n'; if (p) std::free(p); } }; int main() { std::cout << sizeof(char) << '\t' << sizeof(A) << '\t' << sizeof(A(*)[8]) << '\n'; A *a = new A; std::cout << a << '\n'; A *aa = new A[8]; std::cout << aa << '\n'; A (*aaa)[8] = new A[8][8]; std::cout << aaa << '\n'; A (*aaaa)[8][8] = new A[8][8][8]; std::cout << aaaa << '\n'; delete[] aaaa; delete[] aaa; delete[] aa; delete a; } ===== % ./a.exe 1 1 4 A::new(): 0x870668 1 0x870668 A::new[](): 0x870678 12 0x87067c A::new[](): 0x870688 68 0x87068c A::new[](): 0x8706d0 516 0x8706d4 A::delete[](): 0x8706d0 516 A::delete[](): 0x870688 68 A::delete[](): 0x870678 12 A::delete(): 0x870668 1

  • 多次元配列の new 2

    追加の質問ですみません^^; char の8個の配列へのポインタの配列を new する場合などは、以下のサンプルのように typedef しないとかけないんでしょうかね?たとえば、  char (**bb)[8] = new (char (*)[8])[8]; 書きたいように思いますが、これは文法違反ですし・・・^^; ==== サンプル:(iostream の初期化時に、定義した new が呼び出されるかもしれないことを一応考慮して、stdio の関数を使っています^^) #include <new> #include <stdlib.h> #include <stdio.h> void *operator new(std::size_t s) { void *p = malloc(s); fprintf(stderr, "::new(): %p\t%lu\n", p, (unsigned long)s); return p; } void operator delete(void *p) { fprintf(stderr, "::delete(): %p\n", p); if (p) free(p); } void *operator new[](std::size_t s) { void *p = malloc(s); fprintf(stderr, "::new[](): %p\t%lu\n", p, (unsigned long)s); return p; } void operator delete[](void *p) { fprintf(stderr, "::delete[](): %p\n", p); if (p) free(p); } int main() { typedef char (*T)[8]; char (**b)[8] = new T[8]; delete[] b; } ==== % ./a.exe ::new[](): 0x6e01b0 32 ::delete[](): 0x6e01b0

  • 同じ配列またはクラスを、2回以上newしたとき

    ファイルサイズ不定(ただし最大は10KB)のファイルを複数個読み込む際、ファイル個数分の配列を用意し生成するとメモリ不足になりかねないので、 読み込んだデータを使い終わったらすぐに破棄して別のデータを生成するといったような、1つの配列を使い回す方法を考えています。 (読み込んだbyte型の配列データは即座に4byte区切りでint型配列に変換し格納しています) C++なら  int *p;  p = new int[1024*10];  delete p;  p = new int[1024*10];  delete p; みたいな方法で明示的に解放ができますが、 Javaではガーベッジコレクションで自動回収されるので 任意のタイミングで解放できないので、 int p[] = new int[1024*10]; p = null; p = new int[1024*10]; p = null; みたいな方法で試しているのですが、 こういった方法はやっぱりマズいのでしょうか? JAVAヒープの容量を見る限りでは特に変化は見られず、素人の私では判断できないので、もしもご存知の方がいらっしゃればアドバイスいただけると助かります。 よろしくお願いします

    • ベストアンサー
    • Java
  • char型配列について

    基本的なことですが、 char str[5]="Hello"; --> str[0]='H' str[1]='e' str[2]='l' str[3]='l' str[4]='o' str[5]='\0' では、ないのでしょうか? エラーが出ます。 //error C2117: 'str' : 指定された配列には、初期化子が多すぎます。 char str[6]="Hello"; では、コンパイルできます。 ---------------------------------- また、 #include<iostream> using namespace std; int main() { char str[6]="Hello"; cout << str << endl; for(int i=0;i<7;i++) { cout << "i=" << str[i]; if(str[i]=='\0'){cout << " NULL" << endl;} else{cout << endl;} } getchar();return 0; } ----------------------------------------------- とすると、 Hello i=H i=e i=l i=l i=o i= NULL <--ここで、NULLなら、 i=フ <--このぶんは、いらないと思うのですが、、、 となります。 str[6] i=6 は、何を意味するのでしょうか? Visual C++ NET を使用しています。 よろしくお願いします。

  • C++で乱数を重複しないように発生させる

    C++で乱数を重複しないように発生させるようにプログラムを変更しろと言われたのですが、できません。 教えていただきたいです。 #include<iostream> #include<cstdlib> #include<cstring> #include<ctime> using namespace std; int main() { int i,n; int *p; cout<<"何個記憶しますか?"<<endl; cin>>n; p=new int[n]; if(p==NULL){ cout<<"記憶域の確保に失敗しました。"<<endl; return 1; } srand((unsigned)time(NULL)); rand(); i=0; while(i<n){ p[i]=1+(int)((double)rand()/(RAND_MAX+1.0)*75); if(p[i]==p[i]) cout<<"p["<<i<<"]の値"<<p[i]<<endl; i++; } delete[] p; return 0; }

  • メモリ開放の質問ですが

    #include<iostream> using namespace std; void main(void) { int i; char *s,*t; s=new char[9];t=s; for(i=0;i<9;i++)*(s+i)=i; for(i=0;i<9;i++)cout<<(int)s[i]<<endl; delete s; delete t; //error } において2回目のdelete tでエラーになりますが #include<iostream> using namespace std; void main(void) { int i; char *s,*t; s=new char[9];t=s+2; for(i=0;i<9;i++)*(s+i)=i; for(i=0;i<9;i++)cout<<(int)s[i]<<endl; delete t; delete s; } はエラーになりません (s=t+2をs=t+1に変更するとエラーになる) 実際にdeleteは何を行いエラーを引き起こすのでしょうか? エラーになるメカニズムを教えてください

  • int *a = new int; エラー

    下記をコンパイルすると、'int' 型は 'int *' 型に変換できない(関数 main() ) とエラーが出てしまいました。 何がおかしいのでしょうか ? 初歩的な間違いをしていると思いますが、アドバイスお願いします。 #include<iostream> #include<stdlib> #include<ctime> using namespace std; void main(void) { int *a = new int; a=rand(); cout<<a<<endl; delete a; }

  • 条件の配列

    表題の件に付いて質問させていただきます。 複数の条件分岐を簡便に記述する方法を探しております。 簡単な例でいいますと、 int main(){  int value=3;  if(value==0)std::cout <<"value="<<0 <<std::endl;  if(value==1)std::cout <<"value="<<1 <<std::endl;  if(value==2)std::cout <<"value="<<2 <<std::endl;  if(value==3)std::cout <<"value="<<3 <<std::endl; } 上記プログラムの複数の条件分岐をfor文をもちいてかきかえる場合、conditionクラスを作成して class condtion{ private:  int *a;  int b; public  void SetPointer(int* value){a=value}  void SetVal(int val){b=val}  bool isTrue(){   if(*a==b){return true;}   else{ return faulse;}  } } int main(){  int value=3;  condition c[4]; //クラス  for(int i=0;i<4;i++){   c[i]->SetPointer(&value);   c[i]->SetVal(i);  }  for(int i=0; i<4; i++){   if(c[i].isTrue())std::cout<<"i="<<i<<std::endl;  } } と実装できそうな気がするのですが、(上記プログラムは動作確認しておりません。) 変数が増えたり、条件が複雑になると少々繁雑になってしまいそうな気がしております。 もっと簡便に条件分岐を配列として処理する方法は存在しますか? 関数ポインタなどがつかえるのでしょうか? アドバイスよろしくお願いいたします。

  • C++ リストの末尾要素の削除

    連結リストの末尾の要素を削除するプログラムを教えてください。 自分で何度も書き直してみたのですが、どうしてもうまくうごきません。 自分で書いた現状が以下のものですが、止まってしまいます。 void List::removeLast(){ if (head == NULL)return; Cell *p = head; Cell *prev = NULL; while (p!= NULL){ prev = p; p = p->next; } delete prev; } 以下のプログラムが動かすにはremoveLast()をどう変えたらよいのでしょうか? よろしくお願いします。 #include <iostream> using namespace std; // クラスの宣言 class Cell { friend class List; // Listクラスから,このクラスに自由にアクセスできるようにする private: int data; // データ Cell *next; // 次のセルのアドレスを指すポインタ public: Cell(int _data, Cell *n = NULL){ data = _data; next = n; } }; class List { private: Cell *head; // 連結リストの先頭要素のアドレスを指すポインタ public: List(){ head = NULL; }; ~List(){ while (head != NULL)removeFirst(); } void addFirst(int data){ head = new Cell(data, head); } void removeFirst(){ if (head == NULL)return; Cell *removed = head; head = head->next; delete removed; } void removeLast(); void print(){ for (Cell *p = head; p != NULL; p = p->next){ cout << p->data << ' '; } cout << endl; } }; // 連結リストの末尾要素を削除する関数 void List::removeLast() { //この部分です } int main() { List l1; for (int i = 0; i < 10; i++) { l1.addFirst(i); } l1.print(); l1.removeLast(); l1.print(); l1.removeLast(); l1.print(); l1.removeLast(); l1.print(); return 0; } 要求される実行結果は以下の通りです リストの内容: 9 8 7 6 5 4 3 2 1 0 リストの内容: 9 8 7 6 5 4 3 2 1 リストの内容: 9 8 7 6 5 4 3 2 リストの内容: 9 8 7 6 5 4 3

  • ActionScript3.0(アクションスクリプト3.0)でMovieClipインスタンスを配列で生成する方法

    よろしくお願いいたします。 アクションスクリプト3.0において、あるMovieClipクラスから複数のMovieClipインスタンスを作り、それぞれを独立して制御させたい時に、 インスタンスを生成する際、配列でしようとしたのですがエラーとなりうまくいきません。 var my_mc[i]:MovieClip = new MC(); 上記の宣言を繰り返し処理により複数インスタンス生成をしようと思っていました。 MovieClipインスタンスを配列で生成する場合は別の方法があるのでしょうか?それともそもそもできないのでしょうか? また、MovieClipインスタンスをそれぞれ独立して制御させたい場合、別の方法などありますでしょうか? 以上、間違った表現等あるかもしれませんが、よろしくお願いいたします。

    • ベストアンサー
    • Flash

専門家に質問してみよう