私は、C / C ++でプログラミングするときに、メモリに関連する問題がたくさんあると言ったり書いたりする多くのプログラマーを読んだことがあります。私はC/C++でプログラミングすることを学ぶことを計画しています。私はC/C ++の初心者の知識があり、C /C++でメモリ管理に問題が発生する理由の短いサンプルを見たいと思います。いくつかのサンプルを提供してください。
9 に答える
CまたはC++でメモリを破損またはリークする方法はたくさんあります。これらのエラーは、簡単に再現できないことが多いため、診断が最も難しいもののいくつかです。
たとえば、割り当てたメモリの解放に失敗するのは簡単です。たとえば、これは「ダブルフリー」を実行し、a
2回フリーしようとして、フリーに失敗しb
ます。
char *a = malloc(128*sizeof(char));
char *b = malloc(128*sizeof(char));
b = a;
free(a);
free(b); // will not free the pointer to the original allocated memory.
任意のメモリを破壊するバッファオーバーランの例を次に示します。時間がわからないため、バッファオーバーランstr
です。256バイトより長い場合は、それらのバイトをメモリ内のどこかに書き込み、コードを上書きする可能性がありますが、そうでない場合もあります。
void somefunc(char *str) {
char buff[256];
strcpy(buff, str);
}
基本的に、これらの言語では、コンパイル時に既知のローカル変数ではないメモリのすべてのビットを手動で要求する必要があり、不要になったときに手動で解放する必要があります。これらは、このプロセスをある程度自動化できるライブラリ(いわゆるスマートポインタ)ですが、どこにでも適用できるわけではありません。さらに、ポインタ演算を介してメモリにアクセスする(しようとする)方法に制限はありません。
手動のメモリ管理は、いくつかのバグにつながる可能性があります。
- 一部のメモリを解放するのを忘れると、メモリリークが発生します
- 特定のポインタに要求したよりも多くのメモリを使用すると、バッファオーバーランが発生します。
- メモリを解放し、それに「ダングリングポインタ」を使用し続けると、未定義の動作が発生します(通常はプログラムがクラッシュします)
- ポインタ演算を誤って計算すると、クラッシュしたり、データが破損したりします
そして、これらの問題の多くは、診断とデバッグが非常に困難です。
私はC/C++でプログラミングすることを学ぶことを計画しています
それはどういう意味ですか?Cでのプログラミングを学びたいですか、それともC ++でのプログラミングを学びたいですか?両方の言語を同時に学ぶことはお勧めしません。
ユーザーの観点から見ると、C ++でのメモリ管理は、C ++でのメモリ管理よりもはるかに簡単です。これは、そのほとんどがクラスによってカプセル化されているためですstd::vector<T>
。概念的な観点から、Cのメモリ管理ははるかに単純であると主張できます。基本的に、ただmalloc
とfree
:)があります
C ++でプログラミングする場合、メモリ割り当てに「問題」はないと正直に言うことができます。私が最後にメモリリークを起こしたのは10年以上前で、私の側の盲目的な愚かさが原因でした。RAII、標準ライブラリコンテナ、および常識の小さなモディカムを使用してコードを記述した場合、問題は実際には存在しません。
CおよびC++での一般的なメモリ管理の問題の1つは、配列の境界チェックの欠如に関連しています。Java(たとえば)とは異なり、CおよびC ++は、配列インデックスが実際の配列境界内にあることを確認しません。このため、誤ってメモリを上書きする可能性があります。例(C ++):
char *a = new char[10];
a[12] = 'x';
コードが本来あるべきではないメモリを上書きすることを除いて、上記のコードに関連するコンパイルまたはランタイムエラーはありません。
これがC/C ++で異なるものとして一般的に引用される理由は、多くの現代言語がメモリ管理とガベージコレクションを実行するためです。C / C ++では、これは当てはまりません(良くも悪くも)。手動でメモリを割り当てたり、割り当てを解除したりする必要があります。正しく割り当てないと、メモリリークが発生します。これは、メモリ管理を実行する言語では不可能です。
newを使用してメモリのブロックを取得する場合、オペレーティングシステムによって予約されているサイズは、要求よりも大きくなる可能性がありますが、小さくなることはありません。これと、deleteがメモリをオペレーティングシステムにすぐに戻さないという事実のために、プログラムが使用しているメモリ全体を検査すると、アプリケーションに重大なメモリリークがあると思われる可能性があります。したがって、プログラム全体が使用しているバイト数を検査することは、メモリエラーを検出する方法として使用されるべきではありません。メモリマネージャが使用されるメモリの大幅かつ継続的な増加を示した場合にのみ、メモリリークを疑う必要があります。
使用されなくなった、または将来使用されなくなったメモリを解放する必要があることは明らかですが、プログラムの開始時に、メモリ要件が静的であるか、実行時に変化するかを判断する必要があります。動的な場合は、プログラムの作業に十分なメモリを使用するため、プログラムが余分なメモリを消費する可能性があります。
したがって、使用されていないメモリを解放し、必要なときにその時間を作成する必要があります。と同じように
struct student
{
char name[20];
int roll;
float marks;
}s[100];
ここでは、クラスに100人の生徒がいると仮定します。学生は100を超えるか100を下回る可能性があります。100を超えるとプログラムは情報を失い、100を下回るとプログラムは実行されますがメモリの浪費になる可能性があります。
したがって、通常、実行時に動的にレコードを作成します。と同じように
struct student *s;
s=(struct student *)malloc(sizeof(struct student));
scanf("%s %d %f",s->name,s->roll,s->marks);
使用していない場合は、momeryスペースから削除してください。
free(s);
これはプログラミングに適した方法です。メモリから削除しないと、一度にメモリスタックがいっぱいになり、ハングする可能性があります。
これまで言及されていないことの1つは、パフォーマンスと、メモリを手動で管理する理由です。特にプログラムがより複雑になると(特にスレッドを使用する場合やメモリの断片の寿命が複雑になる場合(つまり、断片が必要ない時期を正確に判断するのが難しい場合に困難になる場合)、メモリの管理を正確に行うことは困難です。情報の))valgrindのような強力な最新のプログラミングツールでも。
では、なぜメモリを手動で管理する必要があるのでしょうか。いくつかの理由があります。-メモリの動作を理解するため/ガベージコレクション/自動メモリ管理を実装するには、手動で行う必要があります-カーネルなどの低レベルのものを使用する必要がありますメモリの手動制御がもたらす柔軟性。-最も重要なのは、手動のメモリ管理を正しく行うと、メモリのオーバーヘッドが大幅に高速化/低下し(パフォーマンスが向上)、ガベージコレクションに関連する問題が発生する可能性があることです(ただし、ホットスポットjvmなどのより優れたガベージコレクターが作成されると、より良くなります)メモリ管理を制御できないため、リアルタイムの処理を実行するのが難しいということです(車のブレーキやペースメーカーなどの特定の目的の期限を保証します。
クラス(またはxおよびy C ++機能)を備えたcとは対照的に、多くの「モダンC ++」(C ++は使用方法に応じて複数の言語と見なすことができると言われています)は、単純なオプションを頻繁に使用することで妥協点を使用しますgc /自動メモリ管理(オプションのgcは、メモリ管理がより単純なシステムであるため、必須の場合よりも悪くなる可能性があることに注意してください)機能といくつかの手動メモリ管理。これをどのように行うかに応じて、gcを使用して手動でメモリ管理を行うことにはいくつかの長所と短所があります。オプションのGCは、一部のCライブラリでも使用できますが、c、c++ではあまり一般的ではありません。