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