国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - C/C++ - 深入理解C++中的new和delete并實現對象池

深入理解C++中的new和delete并實現對象池

2022-01-06 13:32-林澤宇 C/C++

這篇文章主要介紹了C++中的new和delete并實現對象池,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下

深入理解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并實現對象池

所以,它們現在混用是沒有問題的?。。?/p>

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

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并實現對象池的文章就介紹到這了,更多相關C++對象池內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!

原文鏈接:https://blog.csdn.net/LINZEYU666/article/details/120206062

延伸 · 閱讀

精彩推薦
  • C/C++深入理解goto語句的替代實現方式分析

    深入理解goto語句的替代實現方式分析

    本篇文章是對goto語句的替代實現方式進行了詳細的分析介紹,需要的朋友參考下...

    C語言教程網7342020-12-03
  • C/C++C++之重載 重定義與重寫用法詳解

    C++之重載 重定義與重寫用法詳解

    這篇文章主要介紹了C++之重載 重定義與重寫用法詳解,本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內容,需要的朋友可以參考下...

    青山的青6062022-01-04
  • C/C++詳解c語言中的 strcpy和strncpy字符串函數使用

    詳解c語言中的 strcpy和strncpy字符串函數使用

    strcpy 和strcnpy函數是字符串復制函數。接下來通過本文給大家介紹c語言中的strcpy和strncpy字符串函數使用,感興趣的朋友跟隨小編要求看看吧...

    spring-go5642021-07-02
  • C/C++C語言實現電腦關機程序

    C語言實現電腦關機程序

    這篇文章主要為大家詳細介紹了C語言實現電腦關機程序,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下...

    xiaocaidayong8482021-08-20
  • C/C++C/C++經典實例之模擬計算器示例代碼

    C/C++經典實例之模擬計算器示例代碼

    最近在看到的一個需求,本以為比較簡單,但花了不少時間,所以下面這篇文章主要給大家介紹了關于C/C++經典實例之模擬計算器的相關資料,文中通過示...

    jia150610152021-06-07
  • C/C++學習C++編程的必備軟件

    學習C++編程的必備軟件

    本文給大家分享的是作者在學習使用C++進行編程的時候所用到的一些常用的軟件,這里推薦給大家...

    謝恩銘10102021-05-08
  • C/C++C語言中炫酷的文件操作實例詳解

    C語言中炫酷的文件操作實例詳解

    內存中的數據都是暫時的,當程序結束時,它們都將丟失,為了永久性的保存大量的數據,C語言提供了對文件的操作,這篇文章主要給大家介紹了關于C語言中文件...

    針眼_6702022-01-24
  • C/C++c++ 單線程實現同時監聽多個端口

    c++ 單線程實現同時監聽多個端口

    這篇文章主要介紹了c++ 單線程實現同時監聽多個端口的方法,幫助大家更好的理解和學習使用c++,感興趣的朋友可以了解下...

    源之緣11542021-10-27
主站蜘蛛池模板: 国产日韩欧美综合 | 久久艹色| 最近中文字幕 | 亚洲一区二区 | 精品日韩在线 | 日韩欧美视频观看 | 成人精品一区二区三区中文字幕 | 91伊人| 日韩一区二区在线播放 | 免费看黄色一级 | 欧美成人精品一区二区 | 黄色免费在线观看 | 欧美大片高清在线观看平台 | 国产精品成人一区二区三区夜夜夜 | 国产精品99一区二区三区 | 91精品国产乱码久久久久久久久 | 狠狠躁夜夜躁人人爽天天天天97 | 欧美精品一区二区三区蜜桃视频 | 久热国产视频 | 少妇精品久久久久久久久久 | 日韩一日 | 北条麻妃99精品青青久久主播 | 91高清在线 | 永久91嫩草亚洲精品人人 | 久久不射电影网 | 午夜精品久久久 | 日韩欧美亚洲精品 | 欧洲精品码一区二区三区免费看 | 国产一区视频网站 | 精品视频一区二区 | 日韩精品视频免费在线观看 | av中文字幕在线观看 | 国产欧美精品一区二区三区 | 四季久久免费一区二区三区四区 | 国产一区二区精品在线观看 | 国产人妖一区 | 最近2019年好看中文字幕视频 | 天堂中文网 | 国产精品不卡一区 | 黄色一级视频在线观看 | 91精品观看 |