• ベストアンサー

【VC++6.0(MFC)】メモリの静的、動的割り当ての意味

いつも大変お世話になっています。 VC++初心者です。 大変初歩的な事なのですが、 理解できていないので質問をさせて頂きたいと思います。 new、deleteはメモリを動的に割り当て、開放しるようですが、 この動的とはどういう意味なのでしょうか。 動的があるのなら、静的にメモリ割り当てというものも あるのでしょうか。 (静的、動的を区別することによって得られる 恩恵とは何なのでしょうか。) 具体的に例を挙げていただけると幸いです。

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

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

>> 「確保される場所が違う」、これをもう少し厳密に言うと >> 「確保されるメモリの場所が違う」という事でしょうか。 >> (例えば、 >> int i;みたいな変数は、Aという範囲のメモリを使いなさい、 >> new を使った変数は、Bという範囲のメモリを使いなさい、 >> というイメージでしょうか。 >> 稚拙な表現ですみません。) 参照URLにも記載されていますが、【int a】で確保した場合、 関数内のauto変数ならスタック領域、static変数やグローバル変数ならば 静的領域に確保されます。 【new】や【malloc】などで確保した場合はヒープ領域に確保されます。 >> >(可変長のCSVファイルを読み込みや、双方向リストなどのデータ構造を作成したい場合) >> >いきなりデカイローカル変数等などを用意して使いまわしても良いと思いますが、実用的ではありません。 >> この内容を拝見して「何故、実用的でないのか」と疑問に思いました。 >> (確かに、あまり良くないな、感覚的には思うのですが、 >>  論理的には説明できないのです。) >> つまり、私の挙げた例を使うと、メモリ範囲Bがあるのに、 >> メモリ範囲Aの部分を大量に消費してしまうから、 >> 実用的でないということでしょうか。 まず、関数内で宣言されるauto変数は、大概の処理系ではスタック領域に確保されるため、 コンパイルオプション等にもよりますが、それほど大きな領域を確保できませんし、 大きな領域を確保出来る環境を前提に作ってしまうと、移植性に乏しくなってしまいます。 newやmallocでメモリを動的に確保出来る利点は以下の通りと私個人では判断しております。 (1)配列では面倒なデータの削除や追加が可能なデータ構造を実現できる。  通常の配列では、途中のデータを追加・削除しようとすると、データのコピー等が発生するなど  処理が重たくなってしまいます。  そこで、リスト構造などデータの追加・削除が容易な仕組みを実現することが必要となり、  自己参照構造体やメモリの動的確保で実現を行います。 (2)例えば、メモリ領域が最大100M確保可能な環境があるとします。  データaとデータbがあり、それぞれ可変長(0~100M)だが、  データaとデータbは足して100Mを超えることは無いものとします。  上記の場合、データa・データbのそれぞれの最大メモリ使用量は100Mのため  足して200Mの領域を最初に確保したいと思いますが、環境が最大100Mまでしか  確保できないため、出来ません。  そこで動的メモリ確保となってくる訳です。 特にオブジェクト指向でプログラムを組むとなると、各タイミングで各種オブジェクトの 生成・消滅が発生します。 それを前提にある程度のオブジェクト数を最初に用意しておく事も可能ですが、コンストラクタや デストラクタを活かすコードを書こうとした場合、new・delete演算子で生成・消滅させた 方が良いと思います。 私はwindows畑ではありませんが、microsoftのMFCなどもウィンドウやボタンを生成する毎に それに対応するCButtonクラス等を継承したクラスを生成していたはずです。 以上

yuki7091
質問者

補足

ご回答、ありがとうございます。 理解できました。(多分、、、) あとは、本当に理解できたか、プログラミングしてみます。 具体的、及び、丁寧な説明、ありがとうございました。

その他の回答 (4)

回答No.4

文字通り動的にメモリを割り当てるという意味です。 つまりプログラム実行中にメモリ領域を確保する操作のことです。 乱暴な説明ですが、プログラムが使用するメモリ領域はコンパイル時 に確定すると考えていただいて差し支えないと思います。 そういう意味ではコンパイラが割り当てるメモリ領域を静的割り当て と呼べるかもしれません。(ただし、C/C++では「静的」という用語は 少し違う意味で使われますので、ここではこれ以上言及しないことに します。) 動的割り当てがどのような場合に使われるかというと、お粗末な例で すが、サイズが予測できないファイルの内容を配列に読み込みたい場合 に、GetFileSize関数などでファイルサイズを取得した後、p = new char[ファイルサイズ]; で適切なメモリ領域を新たに確保します。 蛇足ですが動的に確保したメモリ領域は、用済みになった後deleteで 解放してやらないとプログラム終了までメモリに残ります。いわゆる、 メモリリークという現象ですが、確保するばかりで解放しないといずれ マシンのメモリリソースを食いつぶしてランタイムエラーを引き起こし ます。これはデバッグが難しい割と大きなトラブルです。なのでJava等 ではガーベッジコレクション等の仕組みが用意されています。 さらに蛇足ですが、オブジェクト指向プログラミングでは良くnewが 使われます。これも動的割り当てなのですが、クラスをインスタンス化 する操作であり少し意味合いが異なります。

yuki7091
質問者

補足

ご回答、ありがとうございます。 >つまりプログラム実行中にメモリ領域を確保する操作のことです。 だから、サイズが多き変数、大きさが分からない変数は、動的メモリ確保 (私の例ではBの範囲のメモリ、正確にはヒープ領域に確保)するんですね。 (そうしないと、スタック領域がいっぱいいっぱいになってしまうから?) >プログラムが使用するメモリ領域はコンパイル時 >に確定すると考えていただいて差し支えないと思います。 普通に使用しているメモリ範囲 (私の例ではAの範囲のメモリ、正確にはスタック領域のメモリ) が、コンパイル時に決定されていることは知りませんでした。 (こういう事をきちんと理解すること、ってとても大事な気がしてきました。) 2つ蛇足(?)のアドバイス、ありがとうございます。 私の理解を深める、及び、省みることができました。

回答No.3

参照URLを参照の事。 何か勘違いされているようですが、strcpyはメモリを確保する命令ではありません。 指定されたアドレスに文字列をコピーするだけです。 #1さんのソースコードで配列でもnewでも256バイト確保されます。 ただ、確保される場所が違うだけです。 >>p[5]~p[255]が無駄ということなのでしょうか。 どちらも使わない限り無駄となります。 deleteは確保した時が配列であれば、 delete []p です。 メモリを動的に確保する理由としては可変長のデータに対応するためです。 (可変長のCSVファイルを読み込みや、双方向リストなどのデータ構造を作成した場合) いきなりデカイローカル変数等などを用意して使いまわしても良いと思いますが、実用的ではありません。

参考URL:
http://www9.plala.or.jp/sgwr-t/c/sec12.html
yuki7091
質問者

補足

ご回答、ありがとうございます。 「確保される場所が違う」、これをもう少し厳密に言うと 「確保されるメモリの場所が違う」という事でしょうか。 (例えば、 int i;みたいな変数は、Aという範囲のメモリを使いなさい、 new を使った変数は、Bという範囲のメモリを使いなさい、 というイメージでしょうか。 稚拙な表現ですみません。) >(可変長のCSVファイルを読み込みや、双方向リストなどのデータ構造を作成した場合) >いきなりデカイローカル変数等などを用意して使いまわしても良いと思いますが、実用的ではありません。 この内容を拝見して「何故、実用的でないのか」と疑問に思いました。 (確かに、あまり良くないな、感覚的には思うのですが、  論理的には説明できないのです。) つまり、私の挙げた例を使うと、メモリ範囲Bがあるのに、 メモリ範囲Aの部分を大量に消費してしまうから、 実用的でないということでしょうか。 しかし、その変数たちが関数内などで局所的に宣言されて いるだけならば、関数を抜けた後はその変数は開放されるので、 コーディングの仕方次第では、動的メモリ確保なんてことを しなくても良いのではないでしょうか。

  • Wr5
  • ベストアンサー率53% (2177/4070)
回答No.2

>1回目のstrcpyでは5バイト確保され、 >2回目のstrcpyでは9バイト確保されるということでしょうか。 newの時点で256バイト確保されます。 strcpy()の実行は関係ありません。 静的確保…というかローカル変数の場合、たいていの処理系でスタック領域から取られることが多いです。 が、このスタック領域はたいていの環境においてサイズが有限です。 # VC系の場合、リンカオプションで指定できデフォルトで1Mだったかと。 スタックが1Mの状態で、コールされた関数内でローカル変数を1M以上確保すると…たいていの場合は落ちます。 # スタックオーバーフローになります。 ちなみにstatic変数だったり、グローバル変数の場合はまた別の領域が割り当てられます。 ということで、大きめなサイズのものは動的確保することでスタック領域とは別のヒープ領域から確保しますし。 確保できない場合は関数が失敗したり、ポインタにNULLが返されたり、例外が投げられたり…で自分でエラー処理することも可能です。 # もっとも、ヒープ領域からのメモリがとれない状況ではたいていどうにもならない…と思われますが。 動的確保の他の必要性では… 実行時までサイズが確定できない場合というのもあります。 ファイルをオンメモリで読み込む場合、コーディング時にサイズが確定できないかも知れません。 255バイトで用意して、読み込もうとしているファイルが1Mだったら? じゃあ、1M用意しておいて読み込もうとしたファイルが1.5Mだったら? ならば2M用意しておいて、読み込もうとしたファイルが10Mあったら? という具合に。 ファイルサイズを得る方法がありますので、読み込む前にファイルサイズ分のメモリを確保すれば無駄がありません。 # もっとも、サイズが大きくなったりすると読み込めるだけのメモリ確保が必ずしも成功するとは限らなくなってきますが。

yuki7091
質問者

補足

ご回答、ありがとうございます。 何となく、理解できました。 つまり、動的と静的のデータを保存する場所が違うから、 大きなデータとか、大きさが分からないデータは newする(動的メモリ確保する)、という認識で宜しいでしょうか。 間違っているようならば、ご指摘頂けると幸いです。

  • phoenix343
  • ベストアンサー率15% (296/1946)
回答No.1

new、deleteがプログラム中にあるなら それは動的といえますね。 char *p = new char[256]; strcpy(p, "hoge"); delete p; 逆に単に変数を宣言しているだけなら それは静的といえます。 char p[256]={0}; strcpy(p, "hoge"); 実は静的に確保できるサイズがアプリごとに決まって(リンカのオプションなどで指定する)いて、静的な確保だけだと、効率のよい処理が出来ません。 なので動的に必要なだけ確保して、必要なくなったら解放するという方法がよくとられます。 …と単純に考えてますが 何かもっと別の理由があるなら識者が答えてくれるでしょう 笑

yuki7091
質問者

補足

早速のご回答、ありがとうございます。 #1さんの例ですと、newで動的にメモリを確保した場合、 p[0]には、'h' p[1]には、'o' p[2]には、'g' p[3]には、'e' p[4]には、'null' の5バイトのみが確保され、 変数宣言のみ例の場合、 p[0]には、'h' p[1]には、'o' p[2]には、'g' p[3]には、'e' p[4]には、'null' p[5]には、'' ... p[255]には、'' であり、p[5]~p[255]が無駄ということなのでしょうか。 上記が正しいすると char *p = new char[256]; strcpy(p, "hoge"); strcpy(p, "hogehoge"); delete p; とした場合、 1回目のstrcpyでは5バイト確保され、 2回目のstrcpyでは9バイト確保されるということでしょうか。

関連するQ&A

  • 【VC++6.0(MFC)】スタックメモリサイズの変更方法

    いつも大変お世話になっております。 VC++初心者です。 スタックメモリサイズがデフォルトで1Mが設定されているようですが、 それを確認、及び、変更する方法を教えていただけませんでしょうか。 (具体的には、1.0Mから0.5Mにしたいです。) ちなみに、某サイトで 「プロジェクトのプロパティ→リンカ→システム→スタックのサイズの設定」 で変更可能であるとあったのですが、「プロジェクトのプロパティ」が何を指すのか分かりませんでした。 お手数ですが、よろしくお願いします。

  • CException についてVC6とVC2005とのコンパイルの違い

    こんにちわ、お世話になります。 現在、Windows XPにて、VC++6.0からVC++2005へと あるソフトの移植をしているのですが、 CException についてコンパイルエラーが出ています。 試しに、 -- CException* pException = new CException; delete pException; -- の様な文を書いて、VC++6.0とVC++2005とでコンパイルを 比較してみました。 すると思惑通り、VC++2005でだけ、以下の様なエラーが 出てしまいます。 -- error C2259: 'CException' : 抽象クラスをインスタンス化できません。 1> 次のメンバが原因です: 1> 'CException::~CException(void)' : は抽象型です -- ヘルプを見てもエラーが出るのは納得なのですが、 それならなぜVC++6.0の時には出なかったのでしょうか? 以上、よろしくお願い致します。

  • -メモリ消費について-

    お世話になります。 メモリの消費、及びガベージコレクションについて分からないことがあります。 0 class Child extend Parent{・・・} 1 Parent p = new Parent(); 2 Child c = new Child(); 3 p = c ; 上記のような場合、1行目で確保されたParentのメモリは3行目でChildを参照コピーした時には、どのような状態になるのですか?? メモリの確保、及びに開放、ガベージコレクションについて理解できません。 理解されてる方、助言の方をお願いいたします。

    • ベストアンサー
    • Java
  • C++ newについて

    お世話になっております。C++初心者です。 newについて質問です。 newして動的にメモリを確保したものはdeleteにて解放処理を 行わないとメモリリークしてしまうのはわかっているのですが、 newした動的メモリに再度newをするとどうなるのでしょうか? また、複数回deleteもせずにnewし続けたあとに deleteをした場合はすべて解放されるのでしょうか? 少し気になったので質問してしまいました。 よろしくお願いいたします。

  • 【VC++】MFC、C++/CLI(CLR)、C#の違い、及び、これからの展望

    いつも大変お世話になっています。 VC++初心者です。 VC++6.0(MFC)、VC++2005(CLR)(C++/CLI)(Express Edition)を 同時期に使い始めて何ヶ月か経ちました。 現在では、CLIの方が圧倒的に開発スピードが早く(扱いやすい)、 逆に、MFCの開発スピードが遅く(扱いにくい)、イライラしっぱなしです。 (CLIの開発では、WEBにあるC#のコードを参考にしながら、  コーディングしています。) そこで、何点か疑問に思ったので、ご回答頂けませんでしょうか。 (1)CLIとC#を区別した理由は何なのでしょうか。 (2)MFCはこれからも使われるのでしょうか。  (MFCで新規開発をすることは、まだまだ大勢なのでしょうか。) (3)VC++2005以降、MFCは有償らしいのですが、  VC++6.0(MFC)とVC++2005(MFC)は何か変わったのでしょうか。  (コーディングしやすくなっていますか?) (4)個人差はあると思いますが、開発スピードが一番早いのは、  CLR、C#、MFCのどれでしょうか。   すぐに返信ができないと思いますが、 宜しければ、ご回答頂けると幸いです。

  • メモリについて

    C++で開発を行っています。 メモリ使用量についての質問です。 new でオブジェクトを大量に生成した後、deleteにて開放した場合、 タスクマネージャー上のPF使用量は生成前の状態に戻らないのでしょうか? 自分のマシンでは戻るのですが、他のマシンで確認すると戻りません。 マシンの性能やメモリ使用状態による?異なるのでしょうか? どなたか教えていただけないでしょうか。

  • メモリを増やす?

    最近、使ってるパソコンの動きが遅いなぁと思って知り合いに見せたら「メモリを増やせばいい」と言われました。そして、「そのうちパンクする」とも。 パソコンを最低限使えるだけの技量しかない私には、なんのことやらわかりません。よく聞く言葉なのですがね・・・・(^-^;) メモリを増やすって、具体的に何をすればいいのでしょう?何を買えばいいのでしょう? また、この機会にちゃんと自分でも理解しようかと思いましたので、その辺の初歩的なハードの事を分かりやすく説明してくれているサイト等ありましたら紹介していただければ幸いです。 よろしくお願いします。

  • 【VC++6.0(MFC)】スレッドの呼び出し方について

    いつも大変お世話になっております。 VC++初心者です。 現在、下記のサイトでマルチスレッドを勉強していますが、 そのスレッドの呼び出し方が分かりません。 具体的にどのように書けば宜しいのでしょうか。 http://www.takebay.net/~daigo-ao/paddlewiki.pl/title_4350505FA5B9A5ECA5C3A5C9A4CEBBC8A4A4CAFD5F4D4643C8C7.html mainではないですが、別のクラスから呼び出そうと思い、 以下のように書きましたが、駄目でした。 CHoge aaa; aaa.RunThread(); お手数ですが、よろしくお願い致します。

  • 配列の中身のdelete

    こんにちは 配列を使った際、うまいことDeleteが働いてくれないため メモリが開放されずに困っています、 初歩的な質問で申し訳ありませんが、質問させて下さい。 下記のプログラムでは、 単純にメモリ確保とメモリ開放を行っていると思うのですが… 注釈にもあるように、Deleteでメモリが開放されません。 #include <iostream> using namespace std; class Base { }; class Sub : public Base { char size[256];//領域確保用 }; void main() { Base* obj[10000]; for(int cnt=0;cnt<10000;cnt++) { obj[cnt] = new Sub; } for(int cnt=0;cnt<10000;cnt++) { delete obj[cnt];//メモリが開放されない } } ポインタが怪しいと思うのですが、 どうにかうまいことメモリを開放することは出来ないでしょうか。 よろしければ返答お願いいたします。

  • 【VC++6.0(MFC)】CString型の変数から数字部分を取り出すには?

    いつも大変お世話になっています。 VC初心者です。 現在、VC++6.0(MFC)でコーディングしております。 早速ですが、有識者の方がいらっしゃいましたら ご教授頂きたくお願いします。 ===質問=== CString型変数に以下のような数値を含む文字列から 数値部分だけを取り出すにはどうやってソースを 組めば宜しいでしょうか? ===例01=== CString cs1 = "2009年7月29日"; この文字列から "2009","7","29"を取得したい ===例02=== CString cs2 = "AM10:00:00 -0.4℃"; この文字列から "10","0","0","-0.4"を取得したい 以上、よろしくお願いします。