C/C++ メモリ管理 (C++ での new および delete の使用を含む)


画像

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 区别?
//

  • 说明
    1. スタック はスタックとも呼ばれます。非静的ローカル変数/関数パラメータ/戻り値 などです。スタックは下方向に成長します。
    2. メモリマップドセグメント は、共有ダイナミック メモリ ライブラリをロードするための効率的な I/O マッピング方法です。ユーザーはシステム インターフェイスを使用して、プロセス間通信用の共有共有メモリを作成できます。 (Linuxコースでこれを学習していない場合は、今すぐ理解する必要があります)
    3. ヒープ は、プログラムの実行中に動的メモリ割り当てに使用され、ヒープが増加する可能性があります。
    4. データセグメントグローバル データと静的データを保存します
    5. コードスニペット実行可能コード/読み取り専用定数

したがって、多肢選択式の質問 1 には答えがあります。

そうすると、2. 穴埋め質問の答えは、「以前に習ったことがありますか? (笑)」です。

其中3.sizeofstrlen 区别?

答え: strlen\0 が見つかったときに終了し、strlen は文字列の長さを計算します。sizeof変数のサイズを計算します。


2. C言語による動的メモリ管理方法:malloc/calloc/realloc/free

malloccallocrealloc は C 言語の動的メモリ割り当てに使用される 3 つの関数ですが、主にその機能と使用法にいくつかの違いがあります。

  1. malloc (メモリ割り当て、メモリ割り当て):

    • malloc「メモリ割り当て」の略で、指定したサイズのメモリブロックを割り当てるために使用されます。
    • 初期化せずにメモリを割り当てるだけなので、割り当てられたメモリには任意の値が含まれる可能性があります。
    void* malloc(size_t size);
    
  2. calloc (連続割り当て、連続割り当て):

    • calloc もメモリを割り当てる関数ですが、malloc とは異なり、 calloc によって割り当てられるメモリ ブロックは ゼロに初期化されます
    • calloc必要な要素数と各要素のサイズという 2 つのパラメータを受け入れます。
    void* calloc(size_t num_elements, size_t element_size);
    
  3. 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/deletemalloc/free の最大の違いは、[カスタム タイプ] の new/delete では、スペースを開くだけでなく、コンストラクターとデストラクターも呼び出されることです。< /span>

4. 演算子新規および演算子削除関数

newdelete は、ユーザーが動的メモリを申請および解放するための演算子です。operator newoperator delete は、によって提供されます。グローバル関数、new 最下層operator newグローバル関数を呼び出して、スペースを申請し、 a> グローバル関数。 最下層deleteoperator delete

  • operator new: この関数は、実際には malloc を通じてスペースを適用し、 malloc がスペースの適用に成功した場合、またはスペースの適用に失敗した場合、および再試行した場合に直接戻ります。スペース不足の対策を実装します。ユーザーが対策を設定している場合は適用を続けます。それ以外の場合は例外がスローされます。
  • operator deletefree を通じて最終的に解放されます。
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. 組み込み型

組み込みタイプのスペースを申請する場合、newmallocdelete を返します。 スペース アプリケーションが失敗すると例外をスローします連続スペースを適用し、 は単一要素のスペースに適用および解放されます。/free基本的には似ていますが、相違点は次のとおりです。newdeletenew[]delete[]newmallocNULL

5.2. カスタムタイプ

  • new原理

    1. スペースを申請するためのoperator new関数を呼び出す
    2. 要求されたスペースでコンストラクターを実行して、オブジェクトの構築を完了します。
  • delete原理

    1. スペースに対してデストラクターを実行して、オブジェクト内のリソースのクリーンアップを完了します。
    2. 関数を呼び出しoperator deleteオブジェクトのスペースを解放します

  • new T[N]原理

    1. 関数を呼び出しoperator new[]operator new[] で実際に operator new 関数を呼び出して完了しますN オブジェクト空間のアプリケーション

    2. 要求されたスペースでコンストラクターをN回実行します

  • delete[]原理

    1. 解放されたオブジェクト スペースでデストラクタをN回実行して、N 個のオブジェクトのリソースのクリーンアップを完了します

    2. 呼び出しoperator delete[] でスペースを解放します。実際には operator delete[]operator delete を呼び出してスペースを解放します

ここで、ある現象に注目する必要があります: 組み込み型の場合、 new T[N] の場合、開かれるメモリ空間は N*sizeof(T) より大きくなることがよくあります。アウト4 バイトが多くなる可能性があります。

本来、ここで開かれるスペース サイズptr212*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>、つまり、数値を保存するスペースがありません。 ptr3size4*10 = 4040

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;
}

本来、ここで割り当てられるスペースのサイズptr212*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 の問題の解決策を記録しています。

Xpccccc の github ホームページ

おすすめ

転載: blog.csdn.net/qq_44121078/article/details/134697667