記事ディレクトリ
C/C++ メモリ管理 (C++ での new および delete の使用を含む)
1. C/C++ のメモリ分散
まず、次のコード部分と関連する質問を見てみましょう。
int globalVar = 1; static int staticGlobalVar = 1; int main() { static int staticVar = 1; int localVar = 1; int num1[10] = { 1, 2, 3, 4}; char char2[] = "abcd"; const char *pChar3 = "abcd"; int *ptr1 = (int *) malloc(sizeof(int) * 4); int *ptr2 = (int *) calloc(4, sizeof(int)); int *ptr3 = (int *) realloc(ptr2, sizeof(int) * 4); free(ptr1); free(ptr3); return 0; } //1. 选择题: // 选项: A.栈 B.堆 C.数据段(静态区) D.代码段(常量区) // globalVar在哪里?____ staticGlobalVar在哪里?____ // staticVar在哪里?____ localVar在哪里?____ // num1 在哪里?____ // // char2在哪里?____ *char2在哪里?___ // pChar3在哪里?____ *pChar3在哪里?____ // ptr1在哪里?____ *ptr1在哪里?____ //2. 填空题: // sizeof(num1) = ____; //sizeof(char2) = ____; strlen(char2) = ____; // sizeof(pChar3) = ____; strlen(pChar3) = ____; // sizeof(ptr1) = ____; //3. sizeof 和 strlen 区别? //
- 说明:
- スタック はスタックとも呼ばれます。非静的ローカル変数/関数パラメータ/戻り値 などです。スタックは下方向に成長します。
- メモリマップドセグメント は、共有ダイナミック メモリ ライブラリをロードするための効率的な
I/O
マッピング方法です。ユーザーはシステム インターフェイスを使用して、プロセス間通信用の共有共有メモリを作成できます。 (Linux
コースでこれを学習していない場合は、今すぐ理解する必要があります)- ヒープ は、プログラムの実行中に動的メモリ割り当てに使用され、ヒープが増加する可能性があります。
- データセグメント – グローバル データと静的データを保存します。
- コードスニペット – 実行可能コード/読み取り専用定数。
したがって、多肢選択式の質問 1 には答えがあります。
そうすると、2. 穴埋め質問の答えは、「以前に習ったことがありますか? (笑)」です。
其中3.
sizeof
和strlen
区别?答え:
strlen
は\0
が見つかったときに終了し、strlen
は文字列の長さを計算します。sizeof
変数のサイズを計算します。
2. C言語による動的メモリ管理方法:malloc/calloc/realloc/free
malloc
、calloc
、realloc
は C 言語の動的メモリ割り当てに使用される 3 つの関数ですが、主にその機能と使用法にいくつかの違いがあります。
malloc (メモリ割り当て、メモリ割り当て):
malloc
「メモリ割り当て」の略で、指定したサイズのメモリブロックを割り当てるために使用されます。- 初期化せずにメモリを割り当てるだけなので、割り当てられたメモリには任意の値が含まれる可能性があります。
void* malloc(size_t size);
calloc (連続割り当て、連続割り当て):
calloc
もメモリを割り当てる関数ですが、malloc
とは異なり、calloc
によって割り当てられるメモリ ブロックは ゼロに初期化されます。calloc
必要な要素数と各要素のサイズという 2 つのパラメータを受け入れます。void* calloc(size_t num_elements, size_t element_size);
realloc (再割り当て、再割り当て):
realloc
は割り当てられたメモリのサイズを再割り当てするために使用され、メモリ ブロックのサイズを拡張または縮小するために使用できます。- 元のメモリ ブロックのアドレスが空でない場合
realloc
は、元のアドレスにあるメモリ ブロックのサイズを変更しようとします(新しいメモリ サイズがメモリ ブロックのサイズより大きい場合)。元のアドレスが空の場合、動作はmalloc
と同様になります。void* realloc(void* ptr, size_t new_size);
要約:
malloc
初期化せずに、指定されたサイズのメモリ ブロックのみが割り当てられます。calloc
指定された数とサイズのメモリ ブロックを割り当て、メモリ ブロックのすべてのビットを 0 に初期化します。realloc
メモリ ブロックのサイズを再割り当てします。これを使用して、割り当てられたメモリのサイズを拡大または縮小できます。
int main() { int *p1 = (int *) malloc(sizeof(int)); free(p1); // 1.malloc/calloc/realloc的区别是什么? int *p2 = (int *) calloc(4, sizeof(int)); int *p3 = (int *) realloc(p2, sizeof(int) * 10); // 这里需要free(p2)吗? --- 看情况 free(p3); return 0; }
3. C++ の動的メモリ管理
C 言語のメモリ管理メソッドは C++ でも引き続き使用できますが、一部使用できない箇所 (オブジェクトの初期化など) があり、使用するのがより面倒です。そのためC++ は、独自のメモリ管理方法、つまり new 演算子と delete 演算子による動的メモリ管理を提案しました。
3.1. 新規/削除操作の組み込みタイプ
int main() { // 动态申请一个int类型的空间 int *ptr4 = new int; // 动态申请一个int类型的空间并初始化为10 int *ptr5 = new int(10); cout << *ptr5 << endl; // 动态申请10个int类型的空间 int *ptr6 = new int[3]; // 动态申请10个int类型的空间并初始化前3个 int *ptr7 = new int[3]{ 1, 2, 3}; cout << ptr7[0] << ptr7[1] << ptr7[2] << ptr7[3]; delete ptr4; delete ptr5; delete[] ptr6; delete[] ptr7; }
- 初期化フォーマット:
- 単一要素スペース:
new 类型 (初始化值)
- 連続空間:
new 类型 [元素个数] {从前往后元素初始化值,其余元素初始化为0}
- 注: 単一要素のスペースを適用および解放するには、
new
演算子とdelete
演算子を使用します。申請と解除 連続したスペースの場合は、new[]
とdelete[]
を使用します。注: は を使用して照合されます。
3.2. 新規/削除操作カスタムタイプ
class Date { public: Date() : _year(1), _month(1), _day(1) { cout << "Date()" << endl; } Date(int year, int month, int day) : _year(1), _month(1), _day(1) { _year = year; _month = month; _day = day; cout << "Date()" << endl; } ~Date() { cout << "~Date()" << endl; } private: int _year; int _month; int _day; }; int main() { Date *ptr1 = new Date(); Date *ptr2 = new Date(2, 2, 2); Date *ptr3 = new Date[10]{ { 1, 2, 2}}; free(ptr1); delete ptr2; delete[] ptr3; return 0; }
- 初期化フォーマット:
- 単一要素スペース:
new 类型 (初始化值)
- 連続空間:
new 类型 [元素个数] {从前往后元素初始化值使用{}代表每一个元素的值,其余元素初始化为0}
new/delete
とmalloc/free
の最大の違いは、[カスタム タイプ] のnew/delete
では、スペースを開くだけでなく、コンストラクターとデストラクターも呼び出されることです。< /span>。
4. 演算子新規および演算子削除関数
new
とdelete
は、ユーザーが動的メモリを申請および解放するための演算子です。operator new
とoperator delete
は、によって提供されます。グローバル関数、new
最下層でoperator new
グローバル関数を呼び出して、スペースを申請し、 a> グローバル関数。 の 最下層delete
operator delete
operator new
: この関数は、実際にはmalloc
を通じてスペースを適用し、malloc
がスペースの適用に成功した場合、またはスペースの適用に失敗した場合、および再試行した場合に直接戻ります。スペース不足の対策を実装します。ユーザーが対策を設定している場合は適用を続けます。それ以外の場合は例外がスローされます。operator delete
はfree
を通じて最終的に解放されます。class Date { public: Date() : _year(1), _month(1), _day(1) { cout << "Date()" << endl; } Date(int year, int month, int day) : _year(1), _month(1), _day(1) { _year = year; _month = month; _day = day; cout << "Date()" << endl; } ~Date() { cout << "~Date()" << endl; } private: int _year; int _month; int _day; }; int main() { //operator new -- 不调用构造函数 和 malloc 基本一样 Date *ptr6 = (Date *) operator new(sizeof(Date)); delete new(ptr6) Date; ptr6 = nullptr; return 0; }
5. 新規および削除の実装原則
5.1. 組み込み型
組み込みタイプのスペースを申請する場合、
new
とmalloc
、delete
と を返します。 は 、スペース アプリケーションが失敗すると例外をスローします連続スペースを適用し、 と は単一要素のスペースに適用および解放されます。/free
基本的には似ていますが、相違点は次のとおりです。new
delete
new[]
delete[]
new
malloc
NULL
5.2. カスタムタイプ
new
原理
- スペースを申請するための
operator new
関数を呼び出す- 要求されたスペースでコンストラクターを実行して、オブジェクトの構築を完了します。
delete
原理
- スペースに対してデストラクターを実行して、オブジェクト内のリソースのクリーンアップを完了します。
- 関数を呼び出し
operator delete
オブジェクトのスペースを解放します
new T[N]
原理
関数を呼び出し
operator new[]
、operator new[]
で実際にoperator new
関数を呼び出して完了しますN
オブジェクト空間のアプリケーション要求されたスペースでコンストラクターを
N
回実行します
delete[]
原理
解放されたオブジェクト スペースでデストラクタを
N
回実行して、N 個のオブジェクトのリソースのクリーンアップを完了します呼び出し
operator delete[]
でスペースを解放します。実際にはoperator delete[]
でoperator delete
を呼び出してスペースを解放しますここで、ある現象に注目する必要があります: 組み込み型の場合、
new T[N]
の場合、開かれるメモリ空間はN*sizeof(T)
より大きくなることがよくあります。アウト4
バイトが多くなる可能性があります。本来、ここで開かれるスペース サイズ
ptr2
は12*10 = 120
である必要がありますが、ここでは124
と表示されています。 オブジェクトの数を格納するために使用されます。4
バイトは、開いている連続Date
class Date { public: Date() : _year(1), _month(1), _day(1) { cout << "Date()" << endl; } Date(int year, int month, int day) : _year(1), _month(1), _day(1) { _year = year; _month = month; _day = day; cout << "Date()" << endl; } ~Date() { cout << "~Date()" << endl; } private: int _year; int _month; int _day; }; int main() { Date* ptr1 = new Date; delete ptr1; Date* ptr2 = new Date[10]; delete[] ptr2; return 0; }
ただし、組み込み型の場合
new T[N]
、数値を保存するための追加のスペースは必要ありません。本来、ここで開かれるスペースはであるはずで、ここに表示されます< a i= 4>、つまり、数値を保存するスペースがありません。
ptr3
size
4*10 = 40
40
class Date { public: Date() : _year(1), _month(1), _day(1) { cout << "Date()" << endl; } Date(int year, int month, int day) : _year(1), _month(1), _day(1) { _year = year; _month = month; _day = day; cout << "Date()" << endl; } ~Date() { cout << "~Date()" << endl; } private: int _year; int _month; int _day; }; int main() { Date* ptr1 = new Date; delete ptr1; Date* ptr2 = new Date[10]; delete[] ptr2; int* ptr3 = new int[10]; delete[] ptr3; return 0; }
理由: 追加の
4
バイトは、 < a i を容易にするために、T
サイズの開いた連続スペースの数を記録するために使用されます。 =3> 破壊を実行し、スペースを解放します。delete []
ここでデストラクターを記述しない場合 (デフォルトのメンバー変数ではスペースが開かれません。スペースを空ける場合は、デストラクターを呼び出してスペースを解放する必要があります。そうしないとメモリ リークが発生します)、エラーは発生しません。メンバー変数はすべて組み込み型であるため、レポートされます。空きスペースがなく、デストラクターを呼び出す必要がなく、先頭に
4
バイト数を追加する必要もありません。つまり、カスタム タイプnew T[N]
は直接 a>delete
にすることができ、組み込みタイプにも同じことが当てはまります。class Date { public: Date() : _year(1), _month(1), _day(1) { cout << "Date()" << endl; } Date(int year, int month, int day) : _year(1), _month(1), _day(1) { // _a = new int[10]; _year = year; _month = month; _day = day; cout << "Date()" << endl; } // ~Date() { // cout << "~Date()" << endl; // } private: // int* _a; int _year; int _month; int _day; }; int main() { Date *ptr1 = new Date; delete ptr1; Date *ptr2 = new Date[10]; // 这里如果不写析构函数(默认成员变量没有开辟空间,如果开辟了空间,必须调用析构函数释放空间,不然会内存泄露)的话就不报错 // 因为成员变量都是内置类型没有开空间,不需要调用析构函数,也就不需要在前面添加4字节存个数 delete ptr2; return 0; }
本来、ここで割り当てられるスペースのサイズ
ptr2
は12*10 = 120
である必要があり、ここに表示されます120
。つまり、割り当てられたスペースがないオブジェクトの数。
6. 新しい式を配置します (placement-new)
新しい位置決め式は、コンストラクターを呼び出して、割り当てられた元のメモリ空間内のオブジェクトを初期化します。
- 使用格式:
new (place_address) type
或者new (place_address) type(initializer-list)
place_address
はポインタである必要があります。initializer-list
はタイプの初期化リストです- 使用场景:
- 配置
new
実際には式は通常一致しますメモリプール使用。メモリプールによって確保されたメモリは初期化されないため、カスタム型オブジェクトの場合は、new
の定義式を使用して明示的にコンストラクタを呼び出して初期化する必要があります。class Date { public: Date() : _year(1), _month(1), _day(1) { cout << "Date()" << endl; } Date(int year, int month, int day) : _year(1), _month(1), _day(1) { _year = year; _month = month; _day = day; cout << "Date()" << endl; } ~Date() { cout << "~Date()" << endl; } private: int _year; int _month; int _day; }; int main() { Date *p = (Date *) operator new(sizeof(Date)); // 不能显式调用构造函数 // p->Date(); // 定位new可以显式调用构造函数 new(p)Date(1, 1, 1); p->~Date(); return 0; }
OKOK、C/C++ メモリ管理については以上です。 Linux と C++ にも興味がある場合は、私のホームページをチェックしてください。以下は私の github ホームページで、私が学習したコードと leetcode の問題の解決策を記録しています。