• ベストアンサー

C++言語のポインタについて

現在、C++言語を学習しているのですが、 ポインタを使わない、 int main() { Human human; human.Introduction(); } と、ポインタを使った、 int main() { Human *p; p = new Human; p->Introduction(); delete p; } があります。どちらも同じ動作をしますが、ポインタを使ったものがよく使われているのは、 メモリの節約?動作速度?のためなのでしょうか? なぜ使われるのか教えてください。

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

  • ベストアンサー
  • teuaitou
  • ベストアンサー率32% (10/31)
回答No.1

ポインタを使わない場合、質問文にあるような自動変数だとスタック上にインスタンスが作成されます。スタックサイズが小さい場合でインスタンスのメモリが大きい場合は、スタックがオーバーフローします。newで作成した場合一般的にはヒープ上に作られますから、比較的大きなメモリが使える場合が多いのではないでしょうか。 インスタンス生成とはチョット違いますが、引数で渡すときに、大きな違いが出てきます。値渡しだと、引数で渡される度にコピーコンストラクタが実行されて、スタックを喰い潰していきます。ポインターであれば、コンストラクタは実行されないですし、どんなのサイズの大きいインスタンスでも、ポインタのサイズ分しかスタックを消費しません。

Mokutsuno
質問者

お礼

ありがとうございます

その他の回答 (2)

  • chie65535
  • ベストアンサー率43% (8517/19361)
回答No.3

>どちらも同じ動作をしますが、ポインタを使ったものがよく使われているのは、 >メモリの節約?動作速度?のためなのでしょうか? >なぜ使われるのか教えてください。 前者は「スタック領域」に変数が作られますが、スタック領域は「サイズに限界がある」のです。 Visual Studio 2015でのスタックサイズの指定 https://msdn.microsoft.com/ja-jp/library/tdkhxaks.aspx?f=255&MSPPError=-2147217396 スタックサイズは「例えメモリが余っていたとしても、コンパイル時に指定されたサイズしか確保されない」ので、スタック領域を浪費して「スタックオーバーフロー」が発生すると、メモリを破壊してプログラムが落ちたり、プログラムが予期しない動作をします。 その為「生存期間が長い変数は、new文で、ヒープから動的に確保する」のが常識です。

Mokutsuno
質問者

お礼

わかりました、ありがとうございます

回答No.2

質問の例だと、前者のように書いちゃう事の方が多いと思います。 どちらの方法で書くか検討されるのは、配列なんかとしてそこそこのサイズを確保する場合でしょうか。 (ちなみに、メモリ領域のうちで、前者の変数が確保されるのはスタック領域、後者のメモリが確保されるのはヒープ領域と言われます。) > ポインタを使ったものがよく使われているのは、 > メモリの節約? サイズが可変な場合は、常に最大数を見積もっていると無駄になる場合、ポインタを使って必要な領域を確保します。 あるいは、サイズが相当に大きい場合は、変数を使った場合スタック領域からオーバーフローする場合があるので、ポインタを使う方法が利用されます。 あるいは、質問の例だとHumanのクラスが巨大(?)だったりなら、ポインタ使うかも。 > 動作速度?のためなのでしょうか? 速度に関しては、処理系なんかによるのでどちらが必ず早いとかって事も言えないようです。

Mokutsuno
質問者

お礼

ありがとうございます。クラスの内容にもよるのですね。

関連するQ&A

  • C言語のポインタについて教えてください。

    C言語のポインタについて教えてください。 ・pointer1.c  int main(){   int a;   int *p;   p = &a;     a = 123;   printf("%d", *p);   return 0;  } ・pointer2.c   int main(){ int a[100]; int *p; p = &a[0]; int i; for(i = 0; i < 100; i++) a[i] = i; for(i = 0; i < 100; i++) printf("%d", *p++); return 0; } と二つのソースコードがあるとき、pointer2.cの「p = &a[0]」をpointer1.cのように「p = &a」と書けないのはなぜですか?  また、「&a」は動かすことのできなく、「aを指し示す*p」は動かすことができる変数のようなもの、という認識に誤りはないでしょうか?  宜しくお願いします。

  • 【C言語】別関数でポインタの値を変えたのに変わらない。

    【C言語】別関数でポインタの値を変えたのに変わらない。 メイン関数のポインタの値を、別関数で書き換えるプログラムを作りました。 以下がそのプログラムになります。 そのままだと、ダブルポインタを操作する必要があるので分かり辛いです。なので、ダブルポインタをシングルポインタにしてからポインタの書き換えを行うようにしました。その結果、きちんとポインタの書き換えが出来なくなってしまいました。 なぜ出来なくなってしまったのでしょうか。 2つのプログラムの違いは、 >  *pp = &dummy; が >  p = *pp;      // ダブルポインタをシングルポインタにした >  p = &dummy; に変わっただけです。 【参考】http://www.kouno.jp/home/c_faq/c4.html#8 -----------------正しいプログラム---------------- // 以下プログラムは、正しく動作する // 実行結果は、 //   p = 5 // と表示される void func( int **pp ); int main (void){   int *p;   int a = 0;   p = &a;   func( &p );   printf("p = %d\n", *p);   return 0; } void func( int **pp ){   static int dummy = 5;   *pp = &dummy; } ---------------------------------------------- -----------------間違いプログラム---------------- // 以下プログラムは、正しく動作しない // 実行結果は、 //   p = 0 // と表示される void func( int **pp ); int main (void){   int *p;   int a = 0;   p = &a;   func( &p );   printf("p = %d\n", *p);   return 0; } void func( int **pp ){   static int dummy = 5;   int *p;   p = *pp;      // ダブルポインタをシングルポインタにした   p = &dummy; } ----------------------------------------

  • newされたポインタとdeleteされるポインタが…

    いま私は、std::mapを使って、newされたポインタ(メモリの先頭アドレス)をkeyとして記録し、newされた場所のファイルや行番号、サイズ、何回目のnewか、などなどをvalueとして構造体にまとめて保存してデバッグなどに役立て、deleteされると同時にこの情報を破棄し、最後にすべて破棄されているかどうかを調べる(メモリリークのチェック)という機構を作っています。 ですが、keyとなっているメモリのアドレスは、多重継承や仮想継承とキャストの組み合わせ次第では、newされた時点のものとdeleteされる時点のもので異なっている場合があるため、情報を破棄することができず、行き詰ってしまいました。(無論、delete以外にも情報を引き出す際に影響が…) deleteするポインタから、そのポインタがnewで作成されたときのメモリの先頭アドレスを求める方法はないでしょうか? 以下に問題の部分だけ抽出したようなコードを挙げます。 ---------------- #include <stdio.h> class CLS1{ public: int x,y,z; virtual ~CLS1(){} }; class CLS2{ public: int x,y; virtual ~CLS2(){} }; class CLS3:public CLS1, public CLS2{ public: int x; virtual ~CLS3(){} }; void print(void* p){printf("%p\n",p);} template<typename T> T* create(T* p){ // ここで、たとえば 00854880 と記録されたとして… print(p); return p; } template<typename T> void releace(T* p){ // ここでも 00854880 と記録されてほしいが、 // 00854890 と記録されてしまう。 // この場所で 00854880 と同じインスタンスであることを確かめる方法はないでしょうか? print(p); delete p; } int main(){ CLS2* x = create(new CLS3); // 多重継承しているため、 00854890 と記録される。 print(x); release(x); return 0; }

  • C言語のポインタ

    あまり意識せずにポインタを使っているせいか,次のプログラムではまってしまいました. #include<stdio.h> #include<stdlib.h> int main(void) {  int *p, q;  p = (int *)malloc(sizeof(int));  q = (int *)malloc(sizeof(int));  *p = 2;  printf("%d\n", *p);  return 0; } コンパイルエラーで実行ファイルが出力されません. このプログラムで変数qはなぜポインタじゃないのでしょうか? 次にtypedefでptr_intという型を定義したプログラムは, 上のようなエラーが出力されず,期待とおりの結果になりました. #include<stdio.h> #include<stdlib.h> typedef int* ptr_int; int main(void) {  ptr_int p, q;  p = (int *)malloc(sizeof(int));  q = (int *)malloc(sizeof(int));  *p = 2;  *q = 3;  printf("%d\n", *p);  printf("%d\n", *q); return 0; } typedefすることでなぜエラーを回避することができるのでしょうか? よろしくおねがいします.

  • ポインタ配列の開放について

    いつもお世話になっております。 C++言語初心者です。 ポインタ配列の開放(delete)について質問です。 ※includeは省略します。 int main(){   int *a[10];   for(int i=0;i<10;i++){     a[i]=new int[5];   }   delete[] *a;   return 0; } ポインタ配列を開放する場合、 上記のような書き方で正しいのでしょうか? ただ、上記のような記述方法が間違っている場合、 for(int i=0;i<10;i++){   delete[] a[i]; } とやるのはスマートでない気がするので、 もし他に方法がありましたらお願いします。

  • C言語のポインタについての質問です。

    C言語のポインタについての質問です。 2つのプログラムを作り、片方で数値を入力し、 もう片方でその数値を読み取りたいと思っています。 数値入力のプログラムは次のようになっています。 #include<stdio.h> void main(void){ int A=1; int *p; p=&A; printf("%p\n",p); } この実行結果は「0012FF88」となりました。 次にこの「0012FF88」というアドレスを使って「1」を読み取る 別のプログラムを作りたいと思っています。 #include<stdio.h> void main(void) { int add; int a; printf("アドレスは?\n"); scanf("%x",&add);    //「0012FF88」と入力 a=*(int*)add; printf("%x---->%d",&add,a); } このようなプログラムを作ってコンパイルできたのですが、 実行してアドレスを打ち込むと「Win32の例外が発生しました」 となって実行できません。 何かよい方法やプログラムの問題などありましたら 教えて頂けませんか?

  • ポインタのポインタとrealloc

    先程関数による動的確保について質問させていただき、ヒントを与えていただいたのですが、そこからまた疑問が生じました。 テストプログラムを作ったのですが、何やら動作がおかしいみたいです おかしい部分を抜き出したソースは次のとおりです int main() {  int **p;  int i;  p = (int **)malloc(sizeof(int *));  *p = (int *)malloc(sizeof(int));  p[0]=0;  for(i=1;i<10;i++){   *p = (int *)realloc(*p,sizeof(int)*(i+1));   *p[i] = i;  }  free(*p);  return 0; } 関数部として作りたい部分をメインにして抜き出しました。 このようにするとreallocがメモリ領域を拡張してくれなく(?)、*p[i] = i;の部分でエラー終了します。 ポインタのポインタではなく、ポインタを用いた時は正常に動作するのですが、何がまずいのでしょうか。 もし宜しければお願いいたします。 ちなみに私は学部4年生で、プログラムの使用は大学の研究用レベルです。

  • C言語のポインタのどのあたりが難しいと思いますか?

    C言語のポインタは初心者にとって大きな壁であるとよく言われます。 具体的にポインタのどのあたりが難しいと思いますか? 経験者の方、初心者の方などいろんな意見をお聞かせください。 ちなみに私もポインタでつまづいた人間の一人です。 つまづいた箇所は一箇所ではないのですが、例を挙げるなら int *p; p = &a; *p = a; で pと *pの違いがわからなかったですね…。\0とNULLの違いもごっちゃになっていましたし。 似たような表記だけど意味は違う、という箇所にひっかかっていました。 ポインタがどのようなものなのかというイメージは理解しやすかったのですが…。

  • C言語での関数の引数の受け渡しについて

    C言語での関数の引数の受け渡しについて教えてもらいたいのです。 char *p=Goo;  というポインタpがmain関数で定義され、このポインタpをある関数 void func(・・・) に渡すことは出来ますか? つまりポインタを実引数として扱うことはできるのかという事ですが・・・ int p=10; とかだったら、 void func(int test) の関数には、main関数で func(p) で仮引数testにわたせると思うんですが・・・ もし出来るようでしたら、関数の渡し方と定義の記述を教えてください。 どうか宜しくお願いします。

  • C言語(またはC++言語)についての質問です。

    C言語(またはC++言語)において、以下の変数x、ポインタ変数(*p,**pp, ***ppp)のメモリ上のイメージを記述しなさい。 int x, *p, **pp, ***ppp; x=10; p=&x; pp=&p; pppp=&pp; という問題なのですが、わからなくて困っています。 このプログラムはどのようなものなのでしょうか。 詳しい回答をよろしくお願いします。

専門家に質問してみよう