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