記事ディレクトリ
序文
このブログは、C++ の知識の概要として機能します: new 演算子と detele 演算子
1. C++ メモリ管理
1. 組み込み型
int main()
{
// 动态申请一个int类型的空间
int* p1 = new int; // 未初始化
int* p2 = new int(1); // 初始化
// 动态申请10个连续的int类型的空间
int* p3 = new int[10]; // 未初始化
int* p4 = new int[10] {
1, 2, 3, 4, 5}; // 初始化
delete p1;
delete p2;
delete[] p3;
delete[] p4;
return 0;
}
注: 連続スペースの適用の初期化は、配列の初期化と似ています。
注: 単一要素スペースの適用と解放には、new 演算子と delete 演算子を使用します。連続スペースの適用と解放には、new[] と delete[ を使用します。 ]。
2.カスタムタイプ
class A
{
public:
A(int a = 0)
:_a(a)
{
cout << "A(int a = 0)" << endl;
}
~A()
{
cout << "~A()" << endl;
}
private:
int _a;
};
int main()
{
A* a = new A;
delete a;
cout << "-----------------------------" << endl;
A* aa = new A[10];
delete[] aa;
return 0;
}
注: カスタム型空間を適用する場合、new はコンストラクターを呼び出し、delete はデストラクターを呼び出します。
3. 削除と新規が使用法の問題と一致しません (VS プラットフォーム下)
- 組み込み型の使用法の不一致の問題
int main()
{
int* p1 = new int;
free(p1);
int* p2 = new int[10];
free(p2);
int* p3 = new int;
delete[] p3;
return 0;
}
組み込み型の場合、現時点では削除は解放と同等であるため、プログラムがクラッシュしたりメモリ リークが発生したりすることはありません。ただし、このように使用することはお勧めしません
- カスタムタイプの不一致の問題を使用する
class A1
{
public:
A1(int a = 0)
:_a1(a)
{
cout << "A1(int a = 0)" << endl;
}
// 未写析构函数
/*~A()
{
cout << "~A()" << endl;
}*/
private:
int _a1;
};
class A2
{
public:
A2(int a = 0)
:_a2(a)
{
cout << "A(int a = 0)" << endl;
}
// 写L了析构函数
~A2()
{
cout << "~A()" << endl;
}
private:
int _a2;
};
上記の A1 カテゴリの場合:
プログラムはクラッシュしませんが、空き領域を解放するために使用します。このタイプが領域に適用されると、メモリ リークが発生します。
カテゴリ A2 の場合:
使用法が一致しないとプログラムがクラッシュする可能性がありますが、なぜでしょうか? クラス A1 とクラス A2 の唯一の違いは、デストラクターが明示的に記述されることです。これは、削除により解放された空間のポインタアドレスに問題があるためです。
クラス A2 の場合、new を使用して連続したスペースを開きます。VS は、デストラクターの呼び出し回数を記録するために、開始アドレスの前に余分なスペースを開きます。このとき、スペースの開始アドレスを指す p1 を削除します。 、および delete[] p1 はスペースを指し、開始アドレスの前のスペースのアドレスです。
デストラクタを表示しないクラス A1 の場合、コンパイラは自動的にデストラクタを生成しますが、クラスのメンバ変数の型をコンパイラがチェックし、組み込み型の場合は処理されません。カスタム型である場合、対応する分析が呼び出されます。コンストラクター、クラス A1 の場合、そのメンバー変数は組み込み型であるため、コンパイラーは、デストラクターが呼び出された回数を記録するための余分なスペースを開きません。その後、削除されます。 p1 と delete[] p1 は同じアドレスを指します。
したがって、デストラクターを明示的に記述するカスタム型の場合、使用法が一致しないとプログラムがクラッシュする原因になります。
カテゴリ A2 について別のテストを行うことができます。
プログラムはクラッシュしませんでしたが、デストラクターは 1 回しか呼び出されませんでした。
したがって、一般に、new と delete の使用は一致する必要があります。
2. 演算子新規関数と演算子削除関数
new および delete は、ユーザーが動的メモリを適用および解放するために使用する演算子です。演算子 new および演算子 delete は、システムによって提供されるグローバル関数です。New は、下部にある演算子 new グローバル関数を呼び出してスペースを適用し、delete は演算子 delete を呼び出しますスペースを解放するための下部のグローバル関数。
/*
operator new:该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回;申请空间
失败,尝试执行空 间不足应对措施,如果改应对措施用户设置了,则继续申请,否
则抛异常。
*/
void* __CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{
// try to allocate size bytes
void* p;
while ((p = malloc(size)) == 0)
if (_callnewh(size) == 0)
{
// report no memory
// 如果申请内存失败了,这里会抛出bad_alloc 类型异常
static const std::bad_alloc nomem;
_RAISE(nomem);
}
return (p);
}
/*
operator delete: 该函数最终是通过free来释放空间的
*/
void operator delete(void* pUserData)
{
_CrtMemBlockHeader* pHead;
RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));
if (pUserData == NULL)
return;
_mlock(_HEAP_LOCK); /* block other threads */
__TRY
/* get a pointer to memory block header */
pHead = pHdr(pUserData);
/* verify block type */
_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
_free_dbg(pUserData, pHead->nBlockUse);
__FINALLY
_munlock(_HEAP_LOCK); /* release other threads */
__END_TRY_FINALLY
return;
}
/*
free的实现
*/
#define free(p) _free_dbg(p, _NORMAL_BLOCK)
上記の 2 つのグローバル関数の実装により、演算子 new が実際に malloc を通じてスペースを申請していることがわかります。malloc がスペースの申請に成功した場合は直接戻ります。そうでない場合は、ユーザーが提供したスペース不足の対策が実行されます。ユーザーがこの措置を提供した場合は引き続き適用されますが、それ以外の場合は単なる異常です。オペレーター delete は最終的に free を通じてスペースを解放します。
3. 新規および削除の実装原則
組み込みタイプ
組み込み型スペースを適用する場合、new と malloc、delete と free は基本的に似ていますが、相違点は、new / delete は 1 つの要素のスペースに適用および解放されるのに対し、new[] と delete[] は連続したスペースに適用されることです。さらに、new はスペースの適用に失敗すると例外をスローし、malloc は NULL を返します。
カスタムタイプ
- new の原理
1. 演算子 new 関数を呼び出してスペースを適用します。
2. 適用されたスペースでコンストラクターを実行して、オブジェクトの構築を完了します。 - 削除の原理
1. スペースに対してデストラクターを実行して、オブジェクト内のリソースのクリーンアップを完了します。
2. オペレーターの delete 関数を呼び出して、オブジェクトのスペースを解放します。
class A
{
public:
A(int a = 0)
:_a(a)
{
cout << "A(int a = 0)" << endl;
}
~A()
{
cout << "~A()" << endl;
}
private:
int _a;
};
int main()
{
A* a = new A;
delete a;
return 0;
}
-
new T[n] の原理
1. 演算子 new[] 関数を呼び出し、実際に演算子 new[] 内の演算子 new 関数を呼び出して、n 個のオブジェクト空間に対するアプリケーションを完了します。
2. 適用された空間に対してコンストラクターを N 回実行します。 -
delete[] の原理
1. 解放されたオブジェクト空間で n 個のデストラクターを実行し、n 個のオブジェクト内のリソースのクリーンアップを完了します。
2. 演算子 delete[] を呼び出して領域を解放し、実際に演算子 delete[] で演算子 delete を呼び出して領域を解放します
class A
{
public:
A(int a = 0)
:_a(a)
{
cout << "A(int a = 0)" << endl;
}
~A()
{
cout << "~A()" << endl;
}
private:
int _a;
};
int main()
{
A* a = new A[10];
delete[] a;
return 0;
}
4. malloc/freeとnew/deleteの違い
- 共通点:
malloc/free と new/delete はどちらもヒープからのスペースを適用するため、ユーザーが手動でスペースを解放する必要があります。
- 違い:
使用法(malloc は使いにくい、new は使いやすい):
malloc と free は関数、new と delete は演算子です。malloc
によって適用されるスペースは初期化されません。New は初期化できます。malloc が
スペースに適用する場合、必要があります。スペースのサイズを手動で計算して転送します。新規のみが必要です。スペースのタイプを続けて指定するだけです。複数のオブジェクトがある場合は、[] でオブジェクトの数を指定するだけです。malloc の戻り値は void* です
。使用時に強制されます。new の後にスペースが続くため、New には必要ありません。malloc 型がスペースの
適用に失敗すると、NULL が返されるため、使用時にチェックする必要があります。New は必要ありませんが、new はキャッチする必要があります例外。
カスタム タイプのオブジェクトを適用するときの基本原則 (カスタム タイプの場合)、malloc/free はスペースを開くだけでコンストラクターとデストラクターを呼び出しませんが、new はスペースの適用後にコンストラクターを呼び出してオブジェクトの初期化を完了します。スペースを解放する前に、スペース内のリソースのクリーンアップを完了するためにデストラクターが呼び出されます。
要約する
上記は、new 演算子と delete 演算子に関する私の知識の要約です。ご支援ありがとうございます!!!