【C++初階】七、內存管理(C/C++內存分布、C++內存管理方式、operator new / delete 函數、定位new表達式)

=========================================================================

相關代碼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 mallocdelete 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的區別

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/213471.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/213471.shtml
英文地址,請注明出處:http://en.pswp.cn/news/213471.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

16.Java程序設計-基于SSM框架的android餐廳在線點單系統App設計與實現

摘要&#xff1a; 本研究旨在設計并實現一款基于SSM框架的Android餐廳在線點單系統&#xff0c;致力于提升餐廳點餐流程的效率和用戶體驗。通過整合Android移動應用和SSM框架的優勢&#xff0c;該系統涵蓋了用戶管理、菜單瀏覽與點單、訂單管理、支付與結算等多個功能模塊&…

用戶登錄權限

文章目錄 [TOC](文章目錄) 前言一、 Cookie與session1.HTTP無狀態2.cookie 和 session 的生命周期2.1 cookie 生命周期影響因素2.2 session 生命周期影響因素 3.cookie 和 session 的區別4.工作原理3 用戶登錄Node.js和Express驗證session 二、JSON Web Token1. JWT 介紹2. JWT…

C#使用Matrix類對Dicom圖像的放縮

C#使用Matrix類對Dicom圖像的放縮&#xff0c;使用Matrix 1.同時操作水平、垂直同時放縮 // 創建一個 Matrix 對象 Matrix m_Matrix new Matrix();//放縮參數 float inputZoom1.2f; m_Matrix.Scale(inputZoom, inputZoom, MatrixOrder.Append); 2.操作水平&#xff08;X軸…

前端使用插件預覽pdf、docx、xlsx、pptx格式文件

PDF預覽 H5頁面pdf預覽 插件&#xff1a;pdfh5 版本&#xff1a;“pdfh5”: “^1.4.7” npm install pdfh5 import PdfH5 from "pdfh5"; import "pdfh5/css/pdfh5.css";// methods this.$nextTick(() > {this.pdfH5 new PdfH5("#pdf", {pd…

【算法系列篇】遞歸、搜索和回溯(二)

文章目錄 前言1. 兩兩交換鏈表中的節點1.1 題目要求1.2 做題思路1.3 代碼實現 2. Pow(X,N)2.1 題目要求2.2 做題思路2.3 代碼實現 3. 計算布爾二叉樹的值3.1 題目要求3.2 做題思路3.3 代碼實現 4. 求根節點到葉結點數字之和4.1 題目要求4.2 做題思路4.3 代碼實現 前言 前面為大…

計算機畢業設計springboot+ssm停車場車位預約系統java

管理員不可以注冊賬號 停車位包括車位所在樓層、車位編號、車位類型(全時間開放/高峰期開放)、預定狀態等 用戶預約時要求支付預約時間段的停車費用 違規行為&#xff1a;1.停車超過預約時間段 2.預約未使用 于系統的基本要求 &#xff08;1&#xff09;功能要求&am…

6G來襲,真的有必要嗎?

6G來襲&#xff0c;6G標準將在2025年完成制定&#xff0c;2030年商用。當5G都還沒玩明白的時候&#xff0c;6G又來了。 這次6G又提出了三個全新高大上場景&#xff0c;感知通信、人工智能通信、天地一體泛在物聯&#xff0c;精英們還說&#xff0c;未來要連接很多機器人、元宇宙…

PHP基礎 - 循環與條件語句

循環語句 1)for循環: 重復執行一個代碼塊指定的次數。 for ($i = 0; $i < 5; $i++) { // 初始化 $i 為 0,每次循環后將 $i 值增加 1,當 $i 小于 5 時執行循環echo "The number is: $i \n"; // 輸出當前 $i 的值并換行 }// 循環輸出結果為: // The number …

mysql字段設計規范:使用unsigned(無符號的)存儲非負值

如果一個字段存儲的是數值&#xff0c;并且是非負數&#xff0c;要設置為unsigned&#xff08;無符號的&#xff09;。 例如&#xff1a; 備注&#xff1a;對于類型是 FLOAT、 DOUBLE和 DECIMAL的&#xff0c;UNSIGNED屬性已經廢棄了&#xff0c;可能在mysql的未來某個版本去…

mysql分別在windows和linux下的備份策略

嗟乎&#xff01; 一、概述 mysql數據庫該怎么備份呢&#xff1f; 數據庫備份有幾個概念&#xff1a;全量備份、增量備份、差異備份。當然啦&#xff0c;數據庫備份又有冷備份和熱備份&#xff0c;即物理備份和邏輯備份之分。冷備份就是將mysql停了&#xff0c;然后直接拷貝…

Python入門第2篇

pip包管理器 包管理器類似.NET下的nuget&#xff0c;主要用于管理引用依賴項。 安裝Python的時候&#xff0c;已經默認安裝了pip包管理器&#xff0c;因此無需單獨安裝 cmd&#xff0c;輸入&#xff1a;pip --version 顯示pip版本號信息&#xff0c;即代表pip安裝成功&…

前端知識筆記(四十二)———http和https詳細解析

HTTP&#xff08;Hypertext Transfer Protocol&#xff09;是一種用于在計算機網絡中傳輸超文本的協議。它是一個客戶端-服務器協議&#xff0c;用于從 Web 服務器傳輸超文本到本地瀏覽器。HTTP 使用 TCP/IP 協議作為底層傳輸協議&#xff0c;并使用默認端口號80。 HTTPS&…

8-tornado中模板的使用(通過字符串返回、通過模板Template返回、通過模板render返回)、模板案例

1 Template 1.1 通過字符串返回 import tornado class IndexHandler(web.RequestHandler):def get(self):arg Templateself.finish(f<h1>Hello {arg}!!</h1>)1.2 通過模板Template返回 tornado.template 一個簡單的模板系統&#xff0c;將模板編譯為Python代碼。…

c 一,二,三維數組的定義和賦值

1. 定義數組必須指定數組的大小&#xff0c;也就是用多少存儲空間來存儲此數組 2.定義數組必須用數組的標準格式定義&#xff1a;數組名下標的形式 3.只有字符串可以用指針來定義 4.可以把c 中一切數和struct 理解為char 數組 比如int 就是4字節的char數組 #include <…

編程語言的演進歷程與未來發展趨勢

第一代 編程語言的發展歷程起源于早期的機器語言階段&#xff0c;這是一種由二進制代碼構成的計算機能夠直接解讀并執行的語言。然而&#xff0c;鑒于其過于復雜且難以理解&#xff0c;故這一時代的語言并不常為人類所采納。 第二代 緊接著產生的第二代語言旨在簡化編程過程…

1001 害死人不償命的(3n+1)猜想

卡拉茲(Callatz)猜想&#xff1a; 對任何一個正整數 n&#xff0c;如果它是偶數&#xff0c;那么把它砍掉一半&#xff1b;如果它是奇數&#xff0c;那么把 (3n1) 砍掉一半。這樣一直反復砍下去&#xff0c;最后一定在某一步得到 n1。卡拉茲在 1950 年的世界數學家大會上公布了…

C++ //習題2.5 請寫出下列表達式的值。

C程序設計 &#xff08;第三版&#xff09; 譚浩強 習題2.5 習題2.5 請寫出下列表達式的值。 (1) 3.5 * 3 2 * 7 - ‘a’ (2) 26 / 3 34 % 3 2.5 (3) 45 / 2 (int)3.14159 / 2 (4) a b (c a 6) 設a的初值為3 (5) a 3 * 5, a b 3 * 2 (6) (int)(a 6.5) % 2 …

UI自動化測試工具的定義及重要性

UI自動化測試工具在現代軟件開發中起著不可或缺的作用。它們能夠提高測試效率、減少人為錯誤、提供全面的測試覆蓋&#xff0c;并支持持續集成。通過有效使用UI自動化測試工具&#xff0c;開發團隊可以提高軟件質量&#xff0c;提供更可靠的應用程序&#xff0c;滿足用戶的需求…

C語言之數組精講(2)

目錄 數組的復制 輸入數組元素的值 對數組的元素進行倒序排列 使用數組進行成績處理 對象式宏 數組元素的最大值和最小值 賦值表達式的判斷 數組的元素個數 結語 數組的復制 我們把數組中的元素全部復制到另一個數組中。 #include<stdio.h>int main() {int i;int…

SwinIR: Image Restoration Using Swin Transformer

SwinIR 簡介 論文地址&#xff1a;SwinIR: Image Restoration Using Swin Transformer 代碼&#xff1a;SwinIR ? 本文提出了一個基于swin transformer的圖像超分模型swinIR。其中SwinIR分為三部分&#xff1a;淺層特征提取、深層特征提取和高質量圖像重建模塊。 現階段問…