=========================================================================
相關代碼gitee自取:
C語言學習日記: 加油努力 (gitee.com)
?=========================================================================
接上期:
【C++初階】六、類和對象(初始化列表、static成員、友元、內部類)-CSDN博客
?=========================================================================
? ? ? ? ? ? ? ? ? ? ?
目錄
?? ??一 . C/C++內存分布
C/C++中程序內存區域劃分:
二 . C++內存管理方式
回顧:C語言中動態內存管理方式malloc / calloc / realloc / free
C++的內存管理方式
new / delete --?操作內置類型:
new / delete -- 操作自定義類型:
常見面試題 -- malloc / free 和 new / delete 的區別
三 . operator new 和 operator delete 函數
operator new / operator delete
operator new 全局函數:
operator delete 全局函數:
圖示 -- operator new / delete 全局函數:
new 和 delete 的實現原理
對于內置類型:
(重點)對于自定義類型:
四 . 定位new表達式(placement-new)(了解)
本篇博客相關代碼
Test.cpp文件 -- C++文件:
? ? ? ? ?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
? ? ? ? ? ? ?
一 . C/C++內存分布
? ? ? ? ? ? ? ? ??
C/C++中程序內存區域劃分:
? ? ? ? ? ? ? ? ? ??
不同的數據有不同的存儲需求,內存中有各種區域滿足不同的需求
? ? ? ? ? ? ? ? ??
- 棧(堆棧):
存放非靜態局部變量 / 函數參數 / 返回值 ……,棧是向下增長的
? ? ? ? ? ? ? ? ? ??- 內存映射段:
內存映射段是最高效的 I/O映射方式 ,用于裝載一個共享的動態內存庫。
用戶可以使用系統接口創建共享內存,做進程間通信
? ? ? ? ? ? ? ? ? ? ?- 堆:
用于程序運行時動態內存分配,堆是向上增長的
(動態使用:數據結構、算法中需要動態開辟一些空間)
? ? ? ? ? ? ? ? ? ? ??- 數據段(靜態區):
操作系統角度叫數據段,語言角度叫靜態區。
存儲全局數據和靜態數據
(整個程序運行期間都可能會使用到的數據)
? ? ? ? ? ? ? ?- 代碼段(常量區):
操作系統角度叫代碼段,語言角度叫常量區。
存儲可執行代碼(匯編指令)和常量
(只讀數據)圖示:
? ? ? ? ?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
? ? ? ? ? ? ?
二 . C++內存管理方式
回顧:
C語言中動態內存管理方式malloc / calloc / realloc / free? ? ? ? ? ? ? ??
之前學習C語言的時候有寫過動態內存管理相關內容,
有需要的話可以進行查看:學C的第三十二天【動態內存管理】_高高的胖子的博客-CSDN博客
? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ??
C++的內存管理方式
? ? ? ? ? ? ? ? ? ?
C語言內存管理方式在C++中可以繼續使用,但有些地方就無能為力了,
而且使用起來會比較麻煩,因此C++中又提出了自己的內存管理方式:
通過 new 和 delete 操作符進行動態內存管理
? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ??
new / delete --?操作內置類型:
? ? ? ? ? ? ? ? ??
- new -- 申請單個空間:
? ? ? ? ? ? ? ??內置類型指針 指針名 = new 內置類型;
- new -- 申請多個空間:
? ? ? ? ? ? ? ? ? ? ?內置類型指針 指針名 = new 內置類型[申請單位空間個數];
- new -- 申請單個空間并進行初始化:
? ? ? ? ? ? ? ?內置類型指針 指針名 = new 內置類型(初始化值);
- new -- 申請多個空間并進行初始化:
? ? ? ? ? ? ? ? ? ? ? ?內置類型指針 指針名 = new 內置類型[申請單位空間個數]{第一個初始化值, 第二個初始化值……};
- delete -- 釋放new申請的空間:
? ? ? ? ? ? ? ? ? ?//釋放new申請的單個空間: delete 內置類型指針名; //釋放new申請的多個空間: delete[] 內置類型指針名;
- 對于內置類型的對象申請和釋放,
C++的 new / delete 和 C語言的 malloc / calloc / realloc / free
除了用法上(“強轉”和計算開辟空間大小)外,(底層)幾乎沒有任何區別圖示:
? ? ? ? ? ? ? ? ? ? ? ? ??
? ? ? ? ? ? ? ? ? ? ? ? ??
---------------------------------------------------------------------------------------------? ? ? ? ? ? ? ? ? ? ? ????????
new / delete -- 操作自定義類型:? ? ? ? ? ? ? ? ??
- new -- 申請單個空間:
對于自定義類型,使用C++中的new開辟動態空間的話,
會在開辟空間后順便調用其構造函數進行自定義類型對象的初始化???????? ? ? ? ? ? ? ??//開辟單個空間并自動調用 默認構造函數 進行初始化: 自定義類型指針 指針名 = new 自定義類型; //開辟單個空間并調用 有參構造函數 進行初始化: 自定義類型指針 指針名 = new 自定義類型(初始化值);
- new -- 申請多個空間:
對于自定義類型,使用new申請多個空間時,
同樣會在開辟空間后順便調用其構造函數進行自定義類型對象的初始化???????? ? ? ? ? ? ? ? ? ? ?//方式一:通過有名對象: (先初始化多個自定義類型對象); 自定義類型指針 指針名 = new 自定義類型[申請單位空間個數]{有名對象1, 有名對象2……}; //方式二:通過匿名對象: 自定義類型指針 指針名 = new 自定義類型[申請單位空間個數]{匿名對象1, 匿名對象2……}; //方式三:通過內置類型的隱式類型轉換為自定義類型: 自定義類型指針 指針名 = new 自定義類型[申請單位空間個數]{內置類型1, 內置類型2……};
- delete -- 釋放new申請的空間:
? ? ? ? ? ? ? ? ? ?//釋放new申請的單個空間: delete 自定義類型指針名; //釋放new申請的多個空間: delete[] 自定義類型指針名;
- 對于自定義類型的對象申請和釋放,
C++的?new 除了會開辟動態空間外,還會自動調用其構造函數進行初始化??????????????圖示:
? ? ? ? ? ? ? ? ? ? ? ? ??
? ? ? ? ? ? ? ? ? ? ? ? ??
---------------------------------------------------------------------------------------------? ? ? ? ? ? ? ? ? ? ? ????????
常見面試題 -- malloc / free 和 new / delete 的區別
? ? ? ? ? ? ? ? ? ? ? ?
共同點:
malloc / free 和 new / delete 都是從堆上申請空間的,并且都需要用戶手動釋放
? ? ? ? ? ? ? ? ? ? ? ? ??
? ? ? ? ? ? ? ? ? ? ? ? ??
---------------------------------------------------------------------------------------------? ? ? ? ? ? ? ? ? ? ? ????????
不同點:
- malloc 和 free 是函數 ;new 和 delete 是操作符
? ? ? ? ? ? ? ? ??- malloc 申請的空間不會被初始化 ;new 申請的空間則會被初始化
? ? ? ? ? ? ?- malloc 申請空間時,需要手動計算開辟的空間大小并傳遞;
new 申請空間時,只需要在其后寫出空間的類型即可,
如果是多個對象,[ ]中指定對象個數即可
? ? ? ? ? ? ? ?- malloc 的返回值為 void* ,在使用時必須進行強轉;
new 則不需要,因為 new 后跟的是空間的類型
? ? ? ? ? ? ? ?- malloc 申請空間失敗時,返回的是空指針NULL,因此使用時必須判空;
new 則不需要,但是 new 需要捕獲異常
? ? ? ? ? ? ? ?- 在申請自定義類型對象時:
malloc / free 只會開辟空間,不會調用構造函數和析構函數;
new 在申請空間后會調用構造函數完成對象的初始化,
delete 在釋放空間前會調用析構函數完成空間中資源的清理
? ? ? ? ?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
? ? ? ? ? ? ?
三 . operator new 和 operator delete 函數
operator new / operator delete
? ? ? ? ? ? ??
new 和 delete 是C++中進行動態內存申請和釋放的操作符,
operator new 和 operator delete 是系統提供的全局函數,
new 在底層會調用 operator new 全局函數來申請空間;
delete 在底層會調用 operator delete 全局函數來釋放空間。
? ? ? ? ? ? ??
? ? ? ? ? ? ??
operator new 全局函數:
? ? ? ? ? ? ? ? ??
- 雖然函數名中有 operator ,但并不是重載函數
???????? ? ? ? ? ?- C語言中,malloc 如果申請空間失敗的話,會返回空指針,
這不符合C++面向對象編程的要求,所以需要對其進行封裝
? ? ? ? ? ? ?- operator new 全局函數就是對 malloc 的封裝,
所以 operator new 全局函數底層會調用 malloc ,
讓 malloc 申請空間失敗后會拋出異常,從而能夠符合C++面向對象編程的要求,
operator new 全局函數和 malloc 一樣只會申請空間不會調用構造函數初始化? ? ? ? ? ? ? ? ? ? ? ? ??
? ? ? ? ? ? ? ? ? ? ? ? ??
---------------------------------------------------------------------------------------------? ? ? ? ? ? ? ? ? ? ? ????????
operator delete 全局函數:
? ? ? ? ? ? ? ??
- operator delete 全局函數同樣也不是重載函數,而是一個全局函數
? ? ? ? ? ? ? ?- operator delete 全局函數是對 free 的封裝,
所以 operator delete 全局函數底層會調用 free ,
相較 free ,operator delete 全局函數多了一些檢查,
operator delete 全局函數和 free 一樣只會釋放空間不會調用析構函數? ? ? ? ? ? ? ? ? ? ? ? ??
? ? ? ? ? ? ? ? ? ? ? ? ??
---------------------------------------------------------------------------------------------? ? ? ? ? ? ? ? ? ? ? ????????
圖示 -- operator new / delete 全局函數???????:
? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ??
new 和 delete 的實現原理
? ? ? ? ? ??
對于內置類型:
? ? ? ? ? ? ? ?
如果申請的是內置類型對象的空間,new 和 malloc,delete 和 free 基本類似,
不同的地方是:new / delete 申請和釋放的是單個元素的空間;new[ ] /?delete[ ] 操作的則是連續的空間,
而且 new 在申請空間失敗時會拋出異常,而C語言中malloc則會返回空指針
? ? ? ? ? ? ? ? ? ? ? ??
? ? ? ? ? ? ? ? ? ? ? ? ??
---------------------------------------------------------------------------------------------? ? ? ? ? ? ? ? ? ? ? ????????
(重點)對于自定義類型:
? ? ? ? ? ? ? ??
- new 的原理(申請單個動態空間):
? ? ? ? ? ? ? ? ? ? ? ??
第一步 --? 為自定義類型對象開辟動態空間 -- 調用 operator new 全局函數
(new? =>? operator new? =>? malloc)
? ? ? ? ? ? ? ??
第二步 --? 初始化申請的空間?-- 調用 構造函數 完成對象的初始化
? ? ? ? ? ? ? ? ? ??
? ? ? ? ? ? ? ??- delete 的原理(釋放單個動態空間):
? ? ? ? ? ? ? ? ? ? ?
第一步 --? 先清理自定義類型對象申請的資源?-- 調用對應的?析構函數
? ? ? ? ? ? ? ? ? ? ? ?
第二步 --? 再釋放自定義類型對象的動態空間 -- 調用 operator delete 全局函數
(delete? =>? operator delete? =>? free)
? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ??- new T[N] 的原理(申請多個動態空間):
? ? ? ? ? ? ? ? ??
第一步 --? 調用 operator new[ ] 函數開辟動態空間,
在 operator new[ ] 中實際也是調用了 operator new 全局函數,
一次性完成了N個對象空間的申請
? ? ? ? ? ? ? ?
第二步 --? 在申請的空間上執行N次構造函數,完成N個對象的初始化
? ? ? ? ? ? ? ??
? ? ? ? ? ? ? ?- delete[ ] 的原理(釋放多個動態空間):
? ? ? ? ? ? ? ? ??
第一步 --? 在釋放的對象空間上執行N次析構函數,完成N個對象中資源的清理
? ? ? ? ? ? ? ? ? ?
第二步 --? 調用 operator delete[ ] 釋放空間,
???????在 operator delete[ ] 中實際也是調用了 operator delete 全局函數圖示:
? ? ? ? ?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
? ? ? ? ? ? ?
四 . 定位new表達式(placement-new)(了解)
? ? ? ? ? ? ? ? ? ? ? ? ?
- 定位new表達式是在已分配的原始內存空間中調用構造函數來初始化一個對象
(通過對象指針能夠顯式調用構造函數進行初始化)
? ? ? ? ? ? ? ? ? ??- 使用格式:
調用默認構造函數 -- new (place_address) type
調用有參構造函數 -- new (place_address) type (initializer-list)
place_address:必須是一個指針 ;initializer-list:類型的初始化列表
? ? ? ? ? ? ? ? ? ? ? ??- 使用場景:
定位new表達式在實際中一般是配合內存池進行使用。
因為內存池分配出的內存沒有被初始化,所以如果是自定義類型的對象,
則需要使用new的定位表達式進行顯式調用構造函數來進行初始化圖示:
? ? ? ? ?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
? ? ? ? ? ? ?
本篇博客相關代碼
Test.cpp文件 -- C++文件:
#define _CRT_SECURE_NO_WARNINGS 1#include <iostream> #include <assert.h> using namespace std;全局變量(鏈接屬性:其它文件也可用): //int globalVar = 1; // 靜態全局變量(鏈接屬性:當前文件可用): //static int staticGlobalVar = 1; // //void Test() //{ // //靜態變量(鏈接屬性:函數中可用): // static int staticVar = 1; // // //普通變量: // int localVar = 1; // // //普通數組: // int num1[10] = { 1,2,3,4 }; // // //字符數組: // char char2[] = "abcd"; // /* // * 數組符號:[],本質就是將內容從 // * 常量區(代碼段)復制到棧中 // */ // // //字符指針: // const char* pChar3 = "abcd"; // /* // * 這里沒有使用數組符號[]進行拷貝, // * 所以指針是直接指向常量區中“abcd”的位置的 // */ // // //malloc開辟動態空間: // int* ptr1 = (int*)malloc(sizeof(int) * 4); // //calloc開辟動態空間: // int* ptr2 = (int*)calloc(4, sizeof(int)); // //realloc開辟動態空間: // int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4); //}A類: //class A //{ //public: //公有成員函數: // // //構造函數(全缺省): // A(int a = 0) // : _a(a) // { // //調用則打印: // cout << "A():" << this << endl; // } // // //析構函數: // ~A() // { // //調用則打印: // cout << "~A():" << this << endl; // } // //private: //私有成員變量: // // int _a; //};鏈表結點類: //struct ListNode //{ // int _val; //結點值 // ListNode* _next; //next指針 // // //構造函數: // ListNode(int val) // : _val(val) // , _next(nullptr) // {} // //};主函數: //int main() //{ // //C++動態內存管理(對于內置類型): // int* p1 = new int; //申請單個空間 // // //申請多個空間: // int* p2 = new int[10]; //申請10個單位空間 // //申請40個字節的int數組 -- 后面加:[] // // /* // * 使用new申請動態空間(p1、p2): // * 對于內置類型 -- 申請后不會對空間進行初始化,會是隨機值 // *(對于 p1 和 p2,單純就是開空間) // */ // // //申請動態空間并初始化單個空間: // int* p3 = new int(1); //后面加:(初始化值) // //申請一個int類型的空間并初始化為1 -- 后面加:() // //注意 new int[10] 和 new int(1) 的區別(易混淆) // // //申請動態空間并初始化多個空間: // int* p4 = new int[10] {1,2,3}; // /* // * 后面加:[]{} // * [初始化空間個數]{第一個初始化值,第二個初始化值,第三個初始化值……} // * // * 這里是:[10]{1,2,3} ,即申請了10個單位空間,但只初始化了前3個, // * 之后剩余的7個空間會被默認初始化為0, // * 即開辟的空間為:{1, 2, 3, 0, 0, 0, 0, 0, 0, 0} // */ // // //C++釋放new申請的空間 -- delete: // delete p1; // delete[] p2; // delete p3; // delete[] p4; // // /* // * 總結: // * 對于內置類型的對象申請和釋放, // * 這里 C++的new(delete) 和 // * C語言的malloc/calloc/realloc(free) // * 除了用法上(“強轉”和計算開辟空間大小)外, // * (底層)幾乎沒有任何區別 // */ // // // // // //對于自定義類型: // // //C語言動態內存管理: // A* p5 = (A*)malloc(sizeof(A)); //C語言malloc // /* // * 這里使用了C語言malloc對自定義類型進行動態空間開辟, // * 這里雖然可以開辟,但是無法對其(自定義類型空間)進行初始化, // * 因為這里A類中的成員變量是私有的,無法直接調用 // * // * 所以malloc不方便解決動態申請的自定義類型對象的初始化問題 // */ // // //C++動態內存管理: // A* p6 = new A; //調用默認構造函數(開辟空間后順便初始化) // //new申請動態空間并初始化 -- 自定義類型 // // A* p7 = new A(1); //調用有參構造函數(開辟空間后順便初始化) // //new申請動態空間并初始化 -- 自定義類型 // // /* // * C++中,使用new為自定義類型對象申請空間時, // * 除了會開辟動態空間,還會自動調用其構造函數進行初始化, // * // * new的本質:開辟動態空間 + 調用構造函數初始化 // * // * 解決 C語言中開辟空間后無法進行初始化 的問題 // */ // // //使用new申請一個鏈表結點: // ListNode* n1 = new ListNode(1); //結點1 // ListNode* n2 = new ListNode(2); //結點2 // ListNode* n3 = new ListNode(3); //結點3 // /* // * C++的new帶來的便利: // * 使用new開辟鏈表結點,會在開辟后順便調用其構造函數 // * 進行結點的初始化,不用像C語言中還需要為了開辟結點空間 // * 而單獨設置一個函數 // */ // // // //使用new單詞申請多個鏈表結點: // // //方式一:通過有名對象 // A aa1(1); // A aa2(1); // A aa3(1); // A* p8 = new A[3]{ aa1, aa2, aa3 }; // // //方式二:通過匿名對象 // A* p9 = new A[3]{ A(2), A(2), A(2) }; // // //方式三:將內置類型隱式類型轉化為自定義類型 // A* p10 = new A[3] {3, 3, 3}; // // /* // * 想要對自定義類型初始化,就需要調用其對應類的構造函數, // * 這里要初始化A類型對象,{}大括號中就需要傳A類型對象 // * // * 方式一:A類的有名對象,能找到A類中的構造函數,能初始化 // * // * 方式二:A類的匿名對象,也能找到A類中的構造函數,能初始化 // * // * 方式三: // * 1、內置類型 -> 構造函數 -> 產生臨時對象 // * 2、臨時對象 -> 拷貝構造函數 -> (A類)匿名對象 // -> 找到A類中的構造函數 // */ // // //釋放自定義類型對象空間: // delete p6; // delete[] p10; // /* // * delete對于自定義類型: // * 先調用析構函數銷毀對象清理資源, // * 再調用釋放動態空間, // */ // // return 0; //}//int main() //{ // try // { // char* p1 = new char[0x7fffffff]; // /* // * 十六進制:0x7fffffff -- 接近2G // * // * 當new開辟的空間過大時可能會開辟失敗, // * 開辟失敗則會拋出異常 // *(C語言開辟失敗會返回空指針) // */ // // cout << (void*)p1 << endl; // /* // * char* 在被cout識別時后先被識別為char, // * 而不是我們想要打印的指針(地址), // * 所以要強轉為void*類型 // */ // } // catch (const exception& e) // { // //try……catch……捕獲異常: // cout << e.what() << endl; // } // // // return 0; //}棧類: //class Stack //{ //public: //公有成員函數: // // //構造函數: // Stack(int capacity = 4) // { // //調用了構造函數則打印: // cout << "Stack(int capacity = 4)" << endl; // // //使用new開辟棧容量大小的空間: // _a = new int[capacity]; // // _top = 0; //棧頂值默認為0 // _capacity = capacity; //設置棧容量 // } // // //析構函數: // ~Stack() // { // //調用了析構函數則打印: // cout << "~Stack()" << endl; // // //使用delete釋放new開辟的空間: // delete[] _a; // // _a = nullptr; //置為空指針 // _top = 0; //棧頂值置為0 // _capacity = 0; //棧容量置為0 // } // //private: //私有成員變量: // // int* _a; //棧指針 // int _top; //棧頂值 // int _capacity; //棧容量 // //}; // 主函數: //int main() //{ // Stack s1; // // //使用new申請單個棧對象: // Stack* p1 = new Stack; // //new:開辟空間 + 調用構造函數 // /* // * 這里涉及到兩層空間: // * // * 棧對象開辟空間: // * 先開辟空間,空間大小會自動計算, // * 這里棧的三個私有成員變量大小為12個字節, // * 此時這12字節大小的空間就是對象, // * 此時指針p1就指向這個12個字節的空間 // * // * 棧底層數組開辟空間: // * 開辟空間后,調用構造函數進行初始化: // * _a = new int[capacity]; // * 構造函數中棧底層數組又需要再new一次, // */ // // // //使用delete釋放這個空間: // delete p1; // //delete:調用析構函數 + 釋放空間 // /* // * 這里釋放的空間也有兩層: // * // * 先“銷毀”棧底層數組: // * delete這里需要先調用棧對象的析構函數, // * 來“銷毀”棧底層數組(_a指針指向的數組) // * // * 再釋放整個棧對象: // * 再釋放整個棧對象。如果先釋放棧對象的話, // * 棧底層數據指針_a,就會變成野指針了 // */ // // //operator new 和 operator delete是在庫里面的全局函數, // //封裝了malloc和free: // Stack* p2 = (Stack*)operator new(sizeof(Stack)); // operator delete(p2); // /* // * operator new / operator delete 和 // * new / delete 是不一樣的, // * 但和 malloc / free 是一樣的(用法也一樣), // * // * new / delete 是操作符, // * 而 operator new / operator delete 是函數調用, // * new 除了開辟空間還會調用構造函數初始化空間, // * operator new 和malloc一樣,只會開辟空間不會初始化; // * delete 會先調用析構函數清理空間,再釋放new開辟的空間, // * operator delete 和free一樣,只會釋放空間不會調用析構函數 // * 所以 operator new / operator delete 只是 malloc / free 的封裝 // * // * new 實現的兩步: 1、開辟對象空間 2、調用構造函數初始化 // * 其中第一步中,要實現空間開辟可以使用C語言的malloc, // * 但是malloc失敗只會返回空指針,這不符合面向對象編程的要求, // * 所以需要先對malloc進行封裝,即 operator new , // * operator new 失敗后就可以拋出異常,符合面向對象編程要求, // * 所以new關鍵字的第一步使用的就是malloc封裝后operator new, // * 如果開辟失敗捕獲異常,就不會指向第二步的初始化了 // *(operator new/delete -> 封裝malloc/free -> 處理失敗拋異常問題) // */ // // //上面都是new開辟單個空間,那如果開辟多個空間呢: // Stack* p3 = new Stack[10]; //開辟多個空間 // /* // * new 實現的兩步: 1、開辟對象空間 2、調用構造函數初始化 // * // * 1、開辟對象空間 // * new 開辟單個空間和開辟多個空間同樣都會調用operator new, // * 開辟多個空間實際只會調用一次operator new, // * 一次性就開辟多個連續的空間(這里是10個連續的空間) // *(operator new[] -> operator new -> malloc) // * // * 2、調用構造函數初始化 // * 調用10次Stack構造函數進行初始化 // */ // // delete[] p3; //釋放new開辟的連續空間 // /* // * 1、先調用10次析構函數; // * 2、釋放空間: // * operator delete[] -> operator delete -> free // * // * 補充: // * 前面我們用new開辟了10個連續的空間, // * 按理來說應該是120個字節(這里一個棧對象12個字節), // * 但實際開辟了124個字節,多的4個字節存儲著開辟的空間個數, // * 這里存儲就是10,這樣第一步中就可以知道要調多少次析構函數, // * 第二步中也可以知道釋放時要釋放多少個連續的空間, // * 所以我們使用delete釋放連續空間時“delete[]"中的[], // * 我們不需要顯式寫出要釋放多少個連續空間, // * 因為在用new開辟連續空間的時候就已經存儲好了該值 // *(對于構造函數中申請了資源的自定義類型來說) // * // * 所以 new 要和 delete 配對使用, // * new[] 要和 delete[] 配對使用, // * malloc 要和 free 配對使用 // */ // // return 0; //}//A類: class A { public: //公有成員函數://構造函數(全缺省):A(int a = 0): _a(a){//調用則打印:cout << "A():" << this << endl;}//析構函數:~A(){//調用則打印:cout << "~A():" << this << endl;}private: //私有成員變量:int _a; };int main() {//構造函數只能自動調用:A aa1; //初始化時自動調用//不能顯式調用構造函數:A* p1 = (A*)operator new(sizeof(A)); //開辟動態空間//operator new 不會順便調用構造函數進行初始化//但又不能顯式調用構造函數進行初始化:p1->A(1); //不能像437行那樣顯式調用構造函數,//但可以通過 定位new 顯式調用構造函數:new(p1)A(1);/** 定位new是在已分配的原始內存空間中調用構造函數* 來初始化一個對象* * 格式:* 默認構造:new(對象指針)對象類名* 有參構造:new(對象指針)對象類名(初始化值)*///雖然構造函數不能顯式調用,但析構函數是可以的:p1->~A();//析構函數可以顯式調用也可以自動調用//釋放空間:operator delete(p1);/** 某種程度上來說:* * A* p1 = (A*)operator new(sizeof(A));* +* new(p1)A(1);* * operator new開辟空間配合定位new,可以實現new的功能*(operator new開辟空間,定位new再顯式調用構造函數初始化)*//** 某種程度上來說:* * p1->~A();* +* operator delete(p1);* * p1->~A();顯式調用析構函數配合operator delete釋放空間,* 可以實現delete的功能*//** 雖然可以模擬實現new和delete,* 但一般也不會這么操作* * 因為new有兩步操作,* 1、operator new -> malloc(去堆中申請空間)* 2、調用 構造函數* 所以如果頻繁使用new申請小對象的話,一直去找堆的話,* 效率可能會比較低。* * 這時就需要使用到 內存池,* 把堆的內存較大地申請到內存池中,* 這時當需要申請內存時就不到堆中申請了,* 而是到內存池中申請,不夠了再到堆中申請,* 這時就不用一直到堆中申請,提高效率* 內存池只開了空間,沒有初始化,也不能初始化,* 因為數據可能會是私有的(池化技術)* * 假設我們有一個內存池,在內存池中申請對象空間,* 這時的初始化工作就可以交給 定位new ,* 通過 定位new 顯式調用構造函數來初始化對象,* 這時要釋放空間還給內存池的話,* 就需要顯式調用析構函數來釋放空間*/return 0; }//C++常見面試題:指針和引用的區別、malloc和new的區別