萬盛學電腦網

 萬盛學電腦網 >> 網絡編程 >> 編程語言綜合 >> 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
請按任意鍵繼續. . .
*/
copyright © 萬盛學電腦網 all rights reserved