程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> 更多關於編程 >> C++裸指針和智能指針的效率對比

C++裸指針和智能指針的效率對比

編輯:更多關於編程

      1.unique_ptr與queue連用,unique_ptr的使用特點:不能使用拷貝構造函數,拷貝賦值函數,但是可以使用move構造函數和move賦值函數。

    2.std::move的使用,可以將左值表達式強制轉化成為右值表達式

    3. 重載new操作符調試內存使用情況,因為心裡不是很放心(智能指針真的為我釋放了內存麼?)所以嘗試了重寫new delete操作符。

    4. 得到的結果是raw_ptr:unique_ptr:shared_ptr的性能是5:7:11,可見智能指針的效率還是相當誘人。

    #include <iostream>
    #include <memory>
    #include <Windows.h>
    #include <queue>
    #include <Psapi.h>
    using namespace std;
    
    static size_t	s_my_int_count = 0;
    const  int		MAX_LOOP_ = 3000000;
    
    const int      NORMAL_FLAG = 0x12ff0101;
    const int	   MY_INT_FLAG = 0x12ff0102;
    
    void* operator new(std::size_t size)throw(std::bad_alloc)//重寫new操作符為的是統計我們關心的內存分配
    {
    	int addLen = sizeof(size_t);
    	void * p = std::malloc(addLen + 4 + size) ;
    
    	if (!p)
    		throw std::bad_alloc() ;
    
    	memcpy(p, &size, addLen);//標志實際長度
    	memcpy((char*)p + addLen, &NORMAL_FLAG, 4);//標志類型,普通---0x12ff0101, 我自己的int---0x12ff0102, 我自己的char[]---0x12ff0103
    	return ((char*)p + addLen + 4);
    }
    
    void* operator new(std::size_t size, int flag)throw(std::bad_alloc)// 對應於調用 “new(MY_INT_FLAG) int” 這樣所有我們關心的內存多可以被監視
    {
    	int addLen = sizeof(size_t);
    	void * p = std::malloc(addLen + 4 + size) ;
    
    	if (!p)
    		throw std::bad_alloc() ;
    
    	if (flag == MY_INT_FLAG){
    		s_my_int_count ++;//統計關心的內存申請次數
    	}
    
    	memcpy(p, &size, addLen);//標志實際長度
    	memcpy((char*)p + addLen, &flag, 4);//放置標志位,標志類型,普通---0x12ff0101, 我自己的int---0x12ff0102, 我自己的char[]---0x12ff0103
    	return ((char*)p + addLen + 4);
    }
    
    void operator delete(void * q) throw()
    {
    	void* p;
    	int addLen = sizeof(size_t);
    	p = (char*)q - addLen - 4;//還原原來的指針位置,p是真正的系統malloc出來的指針
    	int flag;
    	memcpy(&flag, (char*)p + addLen, 4);//得到標志位
    	
    	if (flag == MY_INT_FLAG){//統計關心的內存釋放次數
    		s_my_int_count --;
    	}
    
    	if (p)
    		std::free(p) ;
    }
    
    void main(){
    	queue<int*>  intQueue;
    	int count = 0;
    
    	count = 0;
    
    	cout << "before push " << s_my_int_count << " int allocated"<< endl;
    	LONGLONG start = GetTickCount();
    	for (int i = 0; i < MAX_LOOP_; i ++)
    	{
    		int* p = new(MY_INT_FLAG) int;
    		intQueue.push(p);		
    	}
    	cout << "after push " << s_my_int_count << " int allocated"<< endl;
    	while (!intQueue.empty()){
    		int* p = intQueue.front();
    		intQueue.pop();
    		delete p;//注意需要手動釋放
    		count ++;
    	}
    	cout << "after pop " << s_my_int_count << " int allocated"<< endl;
    	cout << "===================raw int ptr for " << count << "t" << GetTickCount() - start << endl;
    
    
    	unique_ptr<int> q(new int);
    	unique_ptr<int> r = move(q);// 編譯正確,r(q) 和 r = q則編譯失敗,因為unique_ptr已經不允許使用“拷貝構造函數”
    
    	queue<unique_ptr<int>> intUniQueue;//因為unique_ptr沒有“拷貝構造函數”  copy-constructor
    	//所以push()的參數不能是“左值”,左值會調用“拷貝構造函數”
    	//只能是“右值”,右值則會調用“移動構造函數” move-constructor,  
    	//std::move()函數可以強制將左值轉化成為右值
    
    	count = 0;
    	start = GetTickCount();	
    	cout << "before push " << s_my_int_count << " int allocated"<< endl;
    	for (int i = 0; i < MAX_LOOP_; i ++)
    	{
    		unique_ptr<int> p(new(MY_INT_FLAG) int);
    		intUniQueue.push(std::move(p));//因為p不是“右值”,所以我們需要“顯式”的調用move將p強制轉為右值。
    	}
    	cout << "after push " << s_my_int_count << " int allocated"<< endl;
    	while (!intUniQueue.empty()){
    		unique_ptr<int> p = std::move(intUniQueue.front());//queue.front() 是一個左值引用,即queue.front()=2 合法。
    		intUniQueue.pop();
    		count ++;
    	}
    	cout << "after pop " << s_my_int_count << " int allocated"<< endl;
    	cout << "===================int unique  ptr for " << count << "t" << GetTickCount() - start << endl;
    
    	queue<shared_ptr<int>> intSharedQueue;
    	count = 0;
    	start = GetTickCount();	
    	cout << "before push " << s_my_int_count << " int allocated"<< endl;
    	for (int i = 0; i < MAX_LOOP_; i ++)
    	{
    		shared_ptr<int> p(new(MY_INT_FLAG) int);
    		intSharedQueue.push(p);
    	}
    	cout << "after push " << s_my_int_count << " int allocated"<< endl;
    	while (!intSharedQueue.empty()){
    		auto p = intSharedQueue.front();
    		intSharedQueue.pop();		
    		count ++;
    	}
    	cout << "after pop " << s_my_int_count << " int allocated"<< endl;
    	cout << "===================int shared ptr for " << count << "t" << GetTickCount() - start << endl;
    
    }
    
    /*
    智能指針省去了我們釋放指針的精力,但是也需要一定的開銷。unique_ptr 的開銷相對於shared_ptr要小很多。
    如果一個資源每個時刻都只要有一個支配者,我們還是優先使用unique_ptr吧,效率會高很多。
    
    before push 0 int allocated
    after push 3000000 int allocated
    after pop 0 int allocated
    ===================raw int ptr for 3000000      5375
    before push 0 int allocated
    after push 3000000 int allocated
    after pop 0 int allocated
    ===================int unique  ptr for 3000000  7313
    before push 0 int allocated
    after push 3000000 int allocated
    after pop 0 int allocated
    ===================int shared ptr for 3000000   11171
    請按任意鍵繼續. . .
    */
    1. 上一頁:
    2. 下一頁:
    Copyright © 程式師世界 All Rights Reserved