中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

C++中new和delete怎么用

發布時間:2021-09-14 17:28:00 來源:億速云 閱讀:110 作者:小新 欄目:開發技術

這篇文章給大家分享的是有關C++中new和delete怎么用的內容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。

new和delete稱作運算符

C++中new和delete怎么用

我們轉反匯編看看

C++中new和delete怎么用

這2個運算符本質也是相應的運算符的重載的調用

malloc和new的區別?

1.malloc按字節開辟內存的;new開辟內存時需要指定類型 new int[10]
所以malloc開辟內存返回的都是void*
而new相當于運算符的重載函數 operator new ->返回值自動轉成指定的類指針 int*
2.malloc只負責開辟空間,new不僅僅有malloc的功能,可以進行數據的初始化

new int(20);//初始化20  
new int[20]();//開辟數組是不支持初始化值的,但是支持寫個空括號,表示給每個元素初始化為0 ,相當于每個元素調用int()成為0

3.malloc開辟內存失敗返回nullptr指針;new拋出的是bad_alloc類型的異常
(也就是說,new運算符開辟內存失敗,要把它的代碼擴在try catch里面,是不能通過返回值和空指針比較的。)

try//可能發生錯誤的代碼放在try里面 
	{
		int *p = new int;
		delete []p;

		int *q = new int[10];
		delete q;
	}
	catch (const bad_alloc &err)//捕獲相應類型的異常 
	{
		cerr << err.what() << endl;//打印錯誤 
	}

C++中new和delete怎么用

free和delete的區別?

delete p: 調用析構函數,然后再free( p),相當于包含了free
如果delete的是普通的指針,那么delete (int*)p和free( p)是沒有區別的
因為對于整型指針來說,沒有析構函數,只剩下內存的釋放

new -> 對operator new重載函數的調用 
delete -> 對operator delete重載函數的調用

把new和delete的重載函數定義在全局的地方,這樣我們整個項目工程中只有涉及到new和delete的地方都會調用到我們全局重寫的new,delete的重載函數。

//先調用operator new開辟內存空間、然后調用對象的構造函數(初始化)
void* operator new(size_t size)
{
	void *p = malloc(size);
	if (p == nullptr)
		throw bad_alloc();
	cout << "operator new addr:" << p << endl;
	return p;
}
//delete p; 先調用p指向對象的析構函數、再調用operator delete釋放內存空間
void operator delete(void *ptr)
{
	cout << "operator delete addr:" << ptr << endl;
	free(ptr);
}

C++中new和delete怎么用
C++中new和delete怎么用

new和delete從內存管理的角度上來說和malloc和free沒有什么區別
除非就是內存開辟失敗,返回不一樣

void* operator new[](size_t size)
{
	void *p = malloc(size);
	if (p == nullptr)
		throw bad_alloc();
	cout << "operator new[] addr:" << p << endl;
	return p;
}
void operator delete[](void *ptr)
{
	cout << "operator delete[] addr:" << ptr << endl;
	free(ptr);
}

C++中new和delete怎么用
C++中new和delete怎么用

C++中,如何設計一個程序檢測內存泄漏問題?
內存泄漏就是new操作沒有對應的delete,我們可以在全局重寫上面這些函數,在new操作里面用映射表記錄都有哪些內存被開辟過,delete的時候把相應的內存資源刪除掉,new和delete都有對應關系
如果整個系統運行完了,我們發現,映射表記錄的一些內存還沒有被釋放,就存在內存泄漏了! 我們用new和delete接管整個應用的所有內存管理 ,對內存的開辟和釋放都記錄
也可以通過編譯器既定的宏和API接口,把函數調用堆棧打印出來,到底在哪個源代碼的哪一頁的哪一行做了new操作沒有delete

new和delete能混用嗎?

C++為什么區分單個元素和數組的內存分配和釋放呢?
下面這樣操作是否可以???

C++中new和delete怎么用

其實現在對于整型來說,沒有所謂的構造函數和析構函數可言,所以這樣的代碼就只剩下malloc和free的功能,所以底層調用的就是malloc和free

C++中new和delete怎么用

所以,它們現在混用是沒有問題的!!!

那什么時候我們才需要考慮這些問題呢?

class Test
{
public:
	Test(int data = 10) { cout << "Test()" << endl; }
	~Test() { cout << "~Test()" << endl; }
private:
	int ma;
};

C++中new和delete怎么用

C++中new和delete怎么用

在這里面,我們能不能混用呢?

C++中new和delete怎么用
C++中new和delete怎么用

出現錯誤了。
此時new和delete不能進行混用了!

C++中new和delete怎么用

C++中new和delete怎么用
C++中new和delete怎么用

在這里,new和delete可以混用嗎?

C++中new和delete怎么用
C++中new和delete怎么用

運行出錯了。

我們最好是這樣配對使用:

new delete
new[] delete[]

對于普通的編譯器內置類型
new/delete[]
new[]/delete
這樣混用是可以的!
因為只涉及內存的開辟和釋放,底層調用的就是malloc和free

但是,如果是對象,就不能混用了。

C++中new和delete怎么用

一個Test對象是4個字節。
每一個Test對象有1個整型的成員變量。

C++中new和delete怎么用

new的時候,分配了5個Test對象,但是不只是開辟了20個字節哦!
delete[]p2的時候先調用Test對象的析構函數,析構函數有this指針,this指針區分析構的對象,this指針把正確的對象的地址傳到析構函數。現在加了[]表示有好幾個對象,有一個數組,里面的每個對象都要析構,但是它是怎么知道是有5個對象呢???
所以,實際上,new Test[5]是開辟了如圖式的內存:
多開辟了4個字節,存儲對象的個數。
用戶在寫new Test[5]時,這個5是要被記錄下來的。
而且,new操作完了之后,給以后返回的p2指針指向的地址是0x104這個地址!即數組首元素的地址。并不是真真正正底層開辟的0x100這個地址,因為那個是不需要讓用戶知道的,用戶只需要知道這個指針指向的是第一個元素對象的地址。

C++中new和delete怎么用

當我們去delete[]p2的時候,它一看這個[]就知道釋放的是一個對象數組,那么就要從p2(0x104)上移4個字節,去取對象的個數,知道是5個對象了(一個對象是4字節),然后把ox104下的內存平均分成5份,每一份內存的起始地址就是對象的起始地址,然后傳給對象的析構函數,就可以進行對象的析構了。然后進行內存的釋放,operator delete(p2-4),從0x100開始釋放!!!

C++中new和delete怎么用
C++中new和delete怎么用

這個代碼錯誤在:實際上開辟的內存空間大小是20+4=24字節,開辟內存是從0028開辟的,因為它有析構函數,所以在底層給數組開辟內存時多開辟了4個字節來存儲開辟的對象的個數,但是用戶返回的是02c,比028剛好多了4個字節,也就是給用戶返回的是真真正正對象的起始地址。
delete p2;它就認為p2只是指向1個對象,因為沒有使用delete[],所以它就只是把Test[0]這個對象析構了而已,然后直接free(p2),從第一個對象的地址(02c)開始free,而底層內存是從028開始開辟的。

我們換成delete[]p2,來運行看看

C++中new和delete怎么用

從指針-4開始free釋放內存的操作

C++中new和delete怎么用

這個代碼的出錯在:只是new出來1個對象,在0x104開辟的,p1也是指向了0x104,但是在delete[]的時候,認為是指向的是對象數組,因為還有析構函數,于是它就從0x104上移4個字節去取開辟對象的個數,

C++中new和delete怎么用

這就出現了問題了。
關鍵是它free的時候,執行的是free(0x104-4)
但是new的時候并不是從0x100開始開辟內存的。

自定義的類類型,有析構函數,為了調用正確的析構函數,那么開辟對象數組的時候,會多開辟4個字節,記錄對象的個數

對象池代碼應用

對象池的實現是靜態鏈表,在堆上開辟的。

C++中new和delete怎么用
C++中new和delete怎么用
C++中new和delete怎么用

#include <iostream>
using namespace std;

template<typename T>
class Queue
{
public:
	Queue()//構造函數 0構造(默認構造) 
	{
		_front = _rear = new QueueItem();
	}
	~Queue()//析構函數 
	{
		QueueItem *cur = _front;//指向頭結點 
		while (cur != nullptr)
		{
			_front = _front->_next;
			delete cur;
			cur = _front;
		}
	}
	void push(const T &val)//入隊操作
	{
		QueueItem *item = new QueueItem(val);//malloc
		_rear->_next = item;
		_rear = item;
	}
	void pop()//出隊操作 隊頭出 頭刪法 
	{
		if (empty())
			return;
		QueueItem *first = _front->_next;
		_front->_next = first->_next;
		if (_front->_next == nullptr)//隊列原本只有1個有效元素節點 
		{
			_rear = _front;
		}
		delete first;//free
	}
	T front()const//獲取首元素的值 
	{
		return _front->_next->_data;
	}
	bool empty()const { return _front == _rear; }//判空  鏈式隊列 
private:
	//產生一個QueueItem的對象池(10000個QueueItem節點)
	struct QueueItem//節點類型,鏈式隊列,帶頭節點的單鏈表 
	{
		QueueItem(T data = T()) :_data(data), _next(nullptr) {}//構造函數
		 
		//給QueueItem提供自定義內存管理
		void* operator new(size_t size)
		{
			if (_itemPool == nullptr)//如果對象池滿了,對象池的指針就指向空了,然后現在進入,再開辟一個對象池 
			{
				_itemPool = (QueueItem*)new char[POOL_ITEM_SIZE*sizeof(QueueItem)];//開辟池 
				QueueItem *p = _itemPool;
				for (; p < _itemPool + POOL_ITEM_SIZE - 1; ++p)//連在一個鏈表上 
				{
					p->_next = p + 1;//因為節點內存是連續開辟的 可以用p+1 
				}
				p->_next = nullptr;
			}

			QueueItem *p = _itemPool;
			_itemPool = _itemPool->_next;
			return p;
		}
		void operator delete(void *ptr)
		{
			QueueItem *p = (QueueItem*)ptr;
			p->_next = _itemPool;
			_itemPool = p;//往頭前放,然后連起來 
		}
		T _data;//數據域 
		QueueItem *_next;//指向下一個節點的指針域 
		static QueueItem *_itemPool;//指向對象池的起始地址,因為所有的 QueueItem都放在一個對象池里面 
		static const int POOL_ITEM_SIZE = 100000;//開辟的對象池的節點的個數,靜態常量可以直接在類體初始化 
	};

	QueueItem *_front;//指向頭節點
	QueueItem *_rear;//指向隊尾 即鏈表的最后一個元素 
};

template<typename T>//在類外定義靜態成員變量 
typename Queue<T>::QueueItem *Queue<T>::QueueItem::_itemPool = nullptr;
//typename告訴編譯器后邊的嵌套類作用域下的名字是類型,放心使用吧 

int main()
{
	Queue<int> que;
	for (int i = 0; i < 1000000; ++i)
	{
		que.push(i);//QueueItem(i)
		que.pop();//QueueItem
	}
	cout << que.empty() << endl;

	return 0;
}

可以把指針改為智能指針,出作用域,對象池自動釋放

感謝各位的閱讀!關于“C++中new和delete怎么用”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

普兰店市| 娄烦县| 宝应县| 武冈市| 龙岩市| 瓦房店市| 玉屏| 瑞昌市| 准格尔旗| 疏附县| 汝南县| 喀什市| 铜鼓县| 青川县| 许昌市| 霍城县| 梅河口市| 紫金县| 广河县| 通榆县| 阳山县| 桑日县| 横山县| 肃北| 个旧市| 镇雄县| 西和县| 辰溪县| 广德县| 阿拉善盟| 大兴区| 罗甸县| 余干县| 枣强县| 尼玛县| 孝昌县| 彩票| 平舆县| 吉隆县| 大丰市| 西和县|