本文比較了裸指針和智能指針的性能 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
請按任意鍵繼續. . .
*/