最近更新したページ
2013-10-20
2013-09-29
2013-09-23
2012-01-07
2011-11-09
2011-10-23
2011-10-09
2011-10-01
2011-09-29
2011-09-03
2011-08-07
2011-08-02
2011-07-29
2011-07-10
2011-05-05
2011-05-04
2011-04-24
2011-04-13
2011-04-05
2011-03-26
2011-02-18
2011-02-15
2010-12-26
2010-12-07
2010-12-05
2010-11-23
2010-09-28
2010-09-23
2010-08-26
2010-08-22
2010-07-16
2010-01-17
2010-01-11
2009-10-04
2009-08-21
2009-08-13
2009-06-18
2009-06-01
2009-04-29
2009-02-16
2009-02-11
2009-02-03
2008-07-22
2008-07-21
2008-07-15
2008-07-14
2008-07-13
2008-07-12
2008-07-08
2008-07-05
2008-06-28
2008-06-17
2008-06-05
2008-06-02
2008-06-01
2008-05-29
2008-05-26
2008-05-21
2008-05-19
2008-05-18
2007-10-31
2007-10-27
2007-09-28
2007-09-23
2007-09-17
2007-09-16
2007-09-14
2007-09-11
2007-06-18
2007-04-15
2006-12-21
2006-11-30
2006-11-22
2006-08-17
2006-03-29
2006-03-28
2006-03-27

C/C++ 動的なメモリ管理


動的なメモリ管理


 C/C++ 配列処理からページ分け。「動的なメモリ管理」の概要については、C/C++ 配列処理 -> 「動的なメモリ管理」を参照。

 C/C++ ... としているが、実際は C++ の new/delete 演算子 利用によるメモリの確保、開放、例外処理についての記載(覚書)であり、.cpp で Win32 ネイティブコード を出力するのに必要な知識の覚書きとなる。CLR(C++/CLI) で作成する場合と異なるとも思われるのであらかじめ注意が必要である。

動的なメモリ管理


メモリ管理とは?


 動的に使用したいメモリの確保・破棄は以上(下にあるので以下だけど...)であるが、実に簡単で、ポインタの理解があれば、すぐにでも利用可能である。

 しかし、動的なメモリ管理には、メモリーリークを出さないコーディング手法が必須となる。例外処理の Try〜catch も難しい訳ではないが、例えば 6つの動的配列を確保した場合、その取得時の例外、実行時の例外、その例外がどの動的配列で発生したかなど、例外発生時の例外処理がプログラム破棄(通常こちらのようであるが...)とするのか、リカバリーを試して再実行を試みる(多分高度で複雑なプログラムを要求され、尚且つ、それに伴う例外処理も処理対象としなければならない...)のか?により難易度が異なる。

 最終目標が、.dll へ、const double 配列 6本 をアドレスで渡し、一時的な double 配列 ?本 へ 一部 copy し、加工した上で1つの値を値渡しで行うことを想定すると、滅多なことで動的メモリ確保と使用上の例外は発生しないと思うが、出来る限りの対策は必要と思われる。

 --- 以下編集中 ---

sample1:動的配列を 2つ確保した場合の例外処理
double *p1 = new double[size];
double *p2 = new double[size];
try {
   // 〜 処理実行 〜      // メモリ確保失敗 -> 例外キャッチ -> 例外処理
}
catch(bad_alloc) {
   // 〜 メモリ割当ての例外キャッチ 〜
   abort();
}
catch(...) {
   // 〜 それ以外の例外キャッチ 〜
   abort();
}
delete [] p;             // メモリ開放(破棄):開放必須

 --- 以上編集中 ---

▲上へ

例外処理の基本


例外処理の基本キーワード


  • 例外処理の基本キーワード
    • try { 〜例外監視〜 }
    • catch { 〜例外処理〜 }
    • throw { 〜例外を投げる場合〜 }

※finally は無いが、例外 catch 後、exit, about, return しなければ、その次の処理へ自動的に移動する。

try { throw b }
catch(a) { 例外 a }
catch(b) { 例外 b }
catch(c) { 例外 c }
// 該当する例外処理後、処理続行。
// 但し、例外処理でプログラム強制終了とか return させてはいけない。
delete p;      // <--- finally 同等として処理可能なのでは?
※finally が有る方が、他言語と共通で混乱しづらいが、C++ は、java より前から有った言語で、尚且つ、java は、C++ を踏み台に作られていることを考えると、やむ終えずと言った感有り。ただ、年数も経つ訳なので C++ 標準となっておかしくない機能と思う。

例外処理の基本プログラムパターン


 散々 finally の利用が出来ないので悩んだが、何のことは無く、各 catch を処理後、exit, about ,return などしなければ、try ... 該当 catch 例外処理後、try , catch を抜け、ストン!と次の処理へ移行する。
 例外処理で次の指示フラグを持たせ、例外全ブロック抜けで 関連全て(又は指示)の動的配列を delete すればよいのではないか?と思われる...(そんな簡単でいいのか?)

※swich 文じゃないので、例外を処理すると次の処理へ速攻移行するのは理屈である。

int size;
try {
    // 例外発生(監視)対象のプログラム
    if (!((size>0)&&(size<100))) { // 1)size が 1-99 以外で例外
        throw 1;
    }                              // else カット
    if (size>=90) {                // 2)90以上で例外"size over!!"送出
        throw "size over!";
    }                              // else カット
    if (size<10) {                 // 3)10以下"Value that cannot be used"送出
        throw "Value that cannot be used.";
    }
    double *pa = new double[size]; // 4)メモリ確保失敗の監視
    〜 処理継続 〜
    delete []pa;
} catch (bad_alloc) {
    // 4.でメモリ確保失敗時の例外処理
} catch (int a) {
    // 1.で int 型の値が投げられた場合の例外処理
} catch (chr *str) {
    // 2.3.の文字列が投げられた場合の例外処理
} catch (...) {
    // 1.2.3.4 の例外に一致しない例外発生時(その他の例外)の処理
    // try ブロック内のその他の例外もキャッチする。
    // この場合、delete []pa; の実行は保証されないようなので注意。
    // exit()  で終了されれば終了処理までされるようである。
    // about() で終了させると終了処理されず確実にメモリーリーク発生。
}
// finally は win32 利用不可。.NET で利用可(参考MSDN:動作は未確認)
/* finally {
    // 必ず実行する処理を記述 *** C++ サポート不明・要確認 ***
    // catch で exit, about なしなら、この処理を最後に実行。
    // ここで delete すれば信頼性が向上?重複 delete の可否不明
}*/
※finally は、ファイル処理・DB処理に必ず使用するので無いと困る。C++ の基本キーワードに見当たらないが使えるのだろうか?
※throw は目新しい機能である。throw を使って swich文の変わりになりそう。
※注:2),3) の例外は、1) で throw されるので絶対に起こりません。あくまで例です。(else 削除で修正動作確認済み)
ゲーロゲロ! C++ の標準規格に finally は無いとの事。使ってみて動いたらめっけもの(...MS謹製なら機能拡張してるかも...)ですが、MSのVC++ 以外移植性の無いプログラムが出来上がることになる。(でも、めんどーなので使えたら使っちゃうね!)
※C++ で finally ステートは、.NET Framework では対応しているようである。(MSDN参照)Win32 の、finally に対する記述は残念ながら確認できず。また、動作確認では、undeclared identifier とか表示されエラーを出す。
※それか、catch 全文に delete を入れると言うのは如何でせう?(間抜けた話になってきた)

▲上へ

C/C++ 例外処理(完全な MS拡張)


以下のキーワードは、MS 拡張の例外処理として存在する。

  • __except
  • __finally
  • __leave
  • __try

#include "windows.h" // これが必要。

おそらく Win32 でも動くと思われるが、try ブロックがまず無いと使えないので、finally のみ取り合えず使おうとしたらエラーになった。面倒なのでこれ以上の言及はしない。

※こっち覚えた方が、後々楽かも…

▲上へ

動的なメモリの確保と破棄

※副題:プログラム実行中に、変数や配列要素の確保と破棄を行う方法
(動的なメモリ確保/破棄(確保と破棄だけなら管理の無い単純コードで可)と、動的なメモリ管理(例外発生時にメモリーリークを出さない仕組みも必要)は異なるレベルと思われるため。)
※以下、C/C++ 配列処理から、C++ の「動的メモリ管理」部分を要点抜粋。(補足・簡略化)

 C++/CLI は、C#, VB, Java のようにメモリ管理(ガベージコレクション)を自動でしてくれるが、.NET 上で動くことが前提のなので「ネイティブコード」にはならない。
 C/C++ は、配列、使用メモリ領域をコンパイル(Build)時にサイズ確定するので、実行時必要な変数領域を増減することが出来ない。
 例として「実行前に入力件数入力、その必要件数分の配列を確保する。」といった簡単なことが、簡単に出来ないのが、C/C++ プログラミングの仕様なのである。

 但し、動的変数、動的配列、動的オブジェクトを使う「動的なメモリ管理」をすることで実現は可能である。

C++ の動的メモリ確保/開放と例外処理


new/delete:動的配列のメモリ割当て
double *p;
try {
   p = new double[size]; // 動的メモリ割当:size は変数可。確保失敗=例外
   // 〜 処理実行 〜      // メモリ確保失敗 -> 例外キャッチ -> 例外処理
}
catch(bad_alloc) {
   // 〜 メモリ割当ての例外キャッチ 〜
   abort();
}
catch(...) {
   // 〜 それ以外の例外キャッチ 〜
   abort();
}
delete [] p;             // メモリ開放(破棄):開放必須
※例外処理を含めた利用が必須。

▲上へ

C/C++ 動的なメモリ割当て方法


言語 メモリ確保メモリ開放領域適用
C malloc()free()ヒープ関数
失敗=NULL
<stdlib.h>
C++ new 演算子 delete 演算子 ヒープ演算子
失敗=例外
<new>
bad_alloc
.cpp なら、new/delete 演算子を使用する。
.c なら malloc()/free() 等を使うしかない。※混在厳禁
※以降、.cpp 利用を前提に new/delete 演算子についてのみ記載。

▲上へ

用語解説


 この辺から、耳慣れない言葉がまた出現する。VB でもオブジェクト指向の、コンストラクタ、デストラクタ、インスタンス、と言った言葉は出ていたが、思いっきり忘れているので再度確認。

※ここに書いてあることは、クラス利用を考慮しない、動的メモリをオブジェクトと捕らえた場合の便宜的解釈。勿論、内容非保証。

コンストラクタ/デストラクタ


コンストラクタ(構築子:Constructor)
オブジェクト指向プログラミングで新しいオブジェクトを生成する際、呼出され初期化などを行なう関数やメソッドの事。
※「動的メモリ」の確保を目的とする場合、new 演算子がコンストラクタにあたると思われる。(解釈非保証/classのコンストラクタと説明的に異なる。)

デストラクタ(消去子:Destructor)
オブジェクト指向のプログラミングでオブジェクト消去の際、呼出され後処理などを行なう関数やメソッドの事。
※「動的メモリ」の開放を目的とする場合、delete 演算子がコンストラクタにあたると思われる。(非保証)
※Java VB C# , C++/CLI(多分コーディングに依存する) など、Java 仮想マシン、.NET Framework 上で動作する先進言語では、デストラクタなどは不要(または存在しない)で、自動的にガベージコレクションによるファイナライザが機能する場合が一般的。そのためプログラム作成者が意識しなくても良い場合が殆どである。(または、意識する必要すら無い)(解釈非保証/classのデストラクタと説明的に異なる。)
※内容非保証ながら、VB や C# などでもデストラクタを使用する局面はあるようである。VB については、DB 使用時の DB 接続に対する開放がこれにあたることを何気に思い出した。(XML あたりもそうなのか?) C# でも明示的にデストラクタ宣言がある。Java はデストラクタが無いらしいが、さすがに DB 接続/切断は必要と思われる。...ちょっと的外れかも知れないがメモ...

▲上へ

インスタンス


インスタンスの生成(instance/instantiation・instantiate)
オブジェクトの実態を指す。具体的にはクラスを元に作成されたオブジェクトの実態。「動的メモリ」だけに絞れば、クラスを利用して構造体型のような物を作成、この型を使用したオブジェクトの生成を行った場合などがこれにあたると思われる。
※クラスを本格的に学習するのでなければ、現状「インスタンス生成」と「オブジェクト生成」を同一と見なしても良いのかなっ?などと思いながら...取り合えず終了。(内容非保証)

▲上へ

オブジェクト


オブジェクトの生成
「動的メモリ確保」のオブジェクト生成は、メモリの割当(allocation)とその初期化(initialization)を行うことを指し、その機能を持つ関数、又は、メソッドをコンストラクタと呼ぶ。
  • オブジェクトの生成(動的変数)::基本形 sample 1-1
int *p;
p = new int;                         // 動的変数(オブジェクト)の作成
delete p;                            // オブジェクトの削除
  • オブジェクトの生成(動的変数)::基本形 sample 1-2
int *p = new int;  // sample 1-1 を1行で纏めて記述。
delete p:
  • オブジェクトの生成(動的変数)::動的配列 sample 2-1
double *p;
p = new double[size];                // 動的配列(オブジェクト)の作成
delete [] p;                         // オブジェクトの削除
  • オブジェクトの生成(動的変数)::動的配列 sample 2-2
double *p = new double[size];
delete [] p;
  • 動的オブジェクト::クラスを使用したオブジェクト生成である。
className *pointer = new className;  // 動的オブジェクトの作成
delete pointer;                      // オブジェクトの削除
※クラスの定義が先であり、動的配列を利用する上で、必ずしも動的オブジェクトを知る必要性は現状無いのでこれは割愛。
※クラスを利用した場合、クラスの有効範囲から外れた場合に、クラスに対応するデストラクタが自動的に delete を行うと言った便利な機能もある。

※上記の例では、一般的に自動的にコンストラクタが呼び出される。動的変数を単体で使用する限りあまり難しく考えない方が良さそう。
※変数そのものもオブジェクト(物)と見れば最も簡単なオブジェクト生成の例と思う。通常はクラスが絡みもっと複雑なようである。
動的配列の定義で見た記述である。

オブジェクト指向
一つの動作を成すプログラムを、一つの物(object)と見做し作成するプログラム開発手法。オブジェクト指向の用件:カプセル化、継承、ポリモーフィズム (多態性)。
要するに、関数、サブルーチンといった主プログラムの一部ではなく、それ自体が1つの役割を演じる物として捕らえ、作成される object の集合... てかっ?「プログラム作成手法の考え方の違い?}のような物か?(内容非保証)
※詳しく続けると、多分クラスとかになだれ込むことになるが、絶対に避けたい!
※C++ は、基本的にオブジェクト指向と言われるが、決してオブジェクト指向プログラムを強要するものではない(...はず...)。
※class などの先進的機能も視野に、.cpp を使ってはいるが、すぐに覚えなければならないものでも無いと現状では判断している。

※大体、このあたりの用語をザックり知っていれば、何とか成る?...かな...?

▲上へ

リンク


内部リンク



外部リンク


  • 現在ありません

▲上へ

独り言


「動的なメモリ管理」と関係の無い独り言とメモなど


C/C++ と C++/CLI


  • C++/CLI
    • .NET のような安全な動作環境上で動作するプログラム開発の統一規格のことと思われる。
      完成プログラムは、先進的な動作安定性を持ち、動的メモリも未使用部分は自動的に開放されたり...と、安全性向上とプログラム作成上の負担が軽減する。
  • C/C++
    • 危険なコードであろうが、プログラム作成者の技量に応じ柔軟なコーディングと高速なネイティブコードを作成できる。
      高速なネイティブコードを期待する場合 VC++ や、Boland C++ 、gcc とか Boland Pascal とか、assembler とか、java でもネイティブコードを出力可能とすることも出来るようである。

※要するに、C++/CLI と言うのは、C/C++ の最大の魅力であるネイティブコード出力を犠牲とし、C++ の難解性を保持しながら、動作の遅い .NET を安全に使いましょう... という C++ 初心者に取っては意味の無い規格といえる。
C/C++ 熟練者から見た場合の魅力もある。.NET への移植性、動作安定性、新言語を覚えなくて良い、C++/CLI の規格とは異なると思うが、コーディングの柔軟性。...とか...

ネイティブコード?


 ここでのネイティブコードとは、(この Wiki では、) x86 native code のことを指す。

 .NET Framework や Java 仮想マシン は、コンパイラにより中間コードを作成、実行時にネイティブコードへ変換してから実行する。... 一般的に遅いが、原則として OS に依存しない(.NET は知りません!でも Win95 でも .NET がインストールできれば動くんぢゃ無いでしょうか?Linux に .Net Framework が移植されれば動くでしょ!...たぶん...)のが特徴である。当然、実行時の安全性も考慮されている。

 要するに機種依存した 機械語をそのまま出力された状態を、ネイティブコードと呼んでいる。(この Wiki での話。)

独り言の独り言


 まず、私が C/C++ のド素人。 -> C++/CLI のメリットが見出せない。 -> C++/CLI については調べる気も無い。 -> その違いについて言及はない。

※.NET ベースなら 難解な C++/CLI を新たに覚えるより、より先進的で開発効率が高いと言われる C# や 初心者でもとっつきやすいと定評の VB を覚えるのが無難と考える。または、資料が豊富な Java ... という個人的見解。

C# って何?


 *S で作った言語仕様(...多分...)なので、オープンでは無いと思われる。.NET 上で動作することが前提なので、Linux で動くことは考えにくいかも...。オープンにはならないと思われるので移植されることも考えにくい...。

 C# や VB 同様、他の OS アプリは作れないと言うことでしょう?...か?(単なる個人的見解)

※C言語/C++ は、Bell研究所所属の個人名が有名、Java は、Sun micro system で公開。C# は、独占欲旺盛な M* ...って感じが拭いきれないのは「わたしだけ〜?」
※C# も無料で使える Express 版がある。始めるのは VC++ VB 他同様に容易である。

▲上へ
2008年05月18日(日) 19:46:37 Modified by cafeboy1




スマートフォン版で見る