程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 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