boost以內存管理

  內存管理一直是令C++程序員最頭疼的工做,C++繼承了C那高效而又靈活的指針,使用起來稍微不當心就會致使內存泄露、野指針、越界訪問等訪問。雖然C++標準提供了只能指針std::auto_ptr,可是並無解決全部問題。boost的smart_ptr庫是對C++98標準的絕佳補充。它提供了六種智能指針,包括scoped_ptr、scoped_array、shared_ptr、shared_array、week_ptr、instrusive_ptr(不建議使用)。如今咱們就學習一下這幾種智能指針的使用方法和注意事項:程序員

#include<boost/smart_ptr.hpp>
#include<boost/smart_ptr/scoped_ptr.hpp>
#include<boost/make_shared.hpp>
#include<boost/enable_shared_from_this.hpp>
#include<string>
#include<vector>
#include<cstdio>
using namespace std;
using namespace boost;
struct posix_file
{
    posix_file(const char* file_name)
    {
        cout<<"open file:"<<file_name<<endl;
    }
    ~posix_file()
    {
        cout<<"close file"<<endl;
    }
};
void any_func(void* p)
{
    cout<<"some operate"<<endl;
}
class self_shared : public enable_shared_from_this<self_shared>
{
public:
    self_shared(int n):x(n){}
    int x;
    void print()
    {
        cout<<"self_shared:"<<x<<endl;
    }
};
void ptr_test()
{
    /*scoped_ptr*/
    scoped_ptr<string> sp(new string("text"));
    cout<<*sp<<endl;
    cout<<sp->size()<<endl;
    //delete sp; 不須要delete
    //scoped_ptr<string> sp1(sp);  不容許,拷貝構造函數爲私有
    //scoped_ptr<string> sp2 = sp; 不容許,賦值函數爲私有
    //sp++; //錯誤,未定義++操做
    scoped_ptr<int> p(new int);
    if(p)  //在bool語境中測試指針是否有效
    {
        *p=100;    //能夠向普通指針同樣使用解引用操做符*
        cout<<*p<<endl;
    }
    p.reset();   //reset()置空scoped_ptr
    if(p==0)
    {
        cout<<"該指針爲空"<<endl;
    }
    if(!p)  //在bool語境中測試,能夠用!操做符
    {
        cout<<"該指針爲空"<<endl;
    }
    //將在離開做用域是自動析構,從而關閉文件釋放資源
    scoped_ptr<posix_file> fp(new posix_file("a.txt"));
    /*auto_ptr 和 scoped_ptr 區別*/
    auto_ptr<int> ap(new int(10));  //一個int的自動指針
    scoped_ptr<int> sp3(ap);  //從 auto_ptr 得到原始指針
    if(ap.get()==0)  //原auto_ptr再也不擁有指針
    {
        cout<<"該指針爲空"<<endl;
    }
    ap.reset(new int(20));   //auto_ptr 擁有新的指針
    cout<<*ap<<","<<*sp3<<endl;

    auto_ptr<int> ap2;
    ap2 = ap; //ap2從ap得到原始指針,發生全部權轉移
    if(ap.get()==0) cout<<"該指針爲空"<<endl; //ap再也不擁有指針
    scoped_ptr<int> sp2;
    //sp2 = sp;    //賦值操做,沒法編譯經過

    /*scoped_array*/
    /*構造函數接受的指針p必須是new[]的結果,而不是new表達式的結果;*/
    /*沒有*和->操做符重載,由於scoped_array持有的不是一個普通的指針*/
    /*析構函數使用delete[]釋放資源,而不是delete*/
    /*提供operator[]操做符重載,能夠向普通數組同樣用下標訪問元素*/
    /*沒用begin()和end()等相似容器的迭代器操做函數*/
    /*不能拷貝不能賦值*/
    scoped_array<int> sa(new int[100]);  //包裝動態數組
    sa[0] = 10;   /*調用[]重載函數 scoped_array 不提供數組索引的範圍檢查*/
    //*(sa+1) = 20; 錯誤用法
    int* arr = new int[100];  //一個整數的動態數組
    scoped_array<int> sa1(arr); //scoped_array 對象代理原始動態數組
    fill_n(&sa1[0],100,5);   //可使用標準庫算法賦值數據
    sa1[10] = sa1[20] + sa1[30]; //使用起來像普通數組
    /*不建議使用scoped_array*/

    /*shared_ptr*/
    /*shared_ptr是一個最像指針的「智能指針」,是boost.smart_ptr庫中最有價值,最重要的組成部分*/
    /*shared_ptr與scoped_ptr同樣包裝了new操做符在堆上分配的動態對象,它實現的是引用計數型的智能指針,能夠自由的拷貝和賦值,能夠安全的放在標準容器中*/
    shared_ptr<int> spi(new int);     //一個int的shared_ptr
    if(!spi) cout<<"該指針爲空"<<endl;  //在bool語境中隱式轉換爲bool值
    *spi=253;  //使用解引用操做符*
    shared_ptr<string> sps(new string("smart"));
    cout<<"該字符串長度:"<<sps->size()<<endl;  //使用箭頭操做符->
    shared_ptr<int> spi1(new int(10));
    if(spi1.unique()) cout<<"是該指針的惟一持有者"<<endl;
    shared_ptr<int> spi2 = spi1;  //調用拷貝構造函數
    //兩個shared_ptr相等,指向同一個對象,引用計數爲2
    cout<<"spi1:"<<spi1.use_count()<<",spi2:"<<spi2.use_count()<<endl;
    shared_ptr<int> spi3 = spi2;
    cout<<"spi1:"<<spi1.use_count()<<",spi2:"<<spi2.use_count()<<",spi3:"<<spi3.use_count()<<endl;
    *spi3=100;
    cout<<"*spi1="<<*spi1<<",*spi2="<<*spi2<<"*spi3="<<*spi3<<endl;
    spi3.reset();   //中止shared_ptr的使用
    cout<<"spi1:"<<spi1.use_count()<<",spi2:"<<spi2.use_count()<<",spi3:"<<spi3.use_count()<<endl;
    if(!spi3) cout<<"該指針爲空"<<endl;
    /*shared_ptr工廠方法*/
    shared_ptr<string> sps1 = make_shared<string>("make_shared");
    shared_ptr<vector<int> > spv = make_shared<vector<int> >(10,2);
    cout<<"spv的大小:"<<spv->size()<<endl;
    cout<<(*spv)[0]<<endl;
    /*shared_ptr應用與標準容器*/
    typedef vector<shared_ptr<int> > vs;
    vs v(10);
    int i=0;
    for(vs::iterator pos = v.begin();pos!=v.end();++pos)
    {
        (*pos) = make_shared<int> (++i);
        cout<<**pos<<endl;  //此處兩次解引用,先得到shared_ptr,在得到其內的值
    }
    shared_ptr<int> pp = v[9];
    *pp = 100;
    cout<<*v[9]<<endl;
    shared_ptr<FILE> fp1(fopen("./1.txt","r"),fclose); //帶有刪除器的shared_ptr,析構的時候調用fclose關閉內部的指針
    /*shared_ptr<void>*/
    shared_ptr<void> vp((void*)0,any_func);  //容納空指針,定製刪除器

    /*shared_array*/
    /*shared_array構造函數接受的指針p必須是new[]的結果,而不能是new表達式的結果*/
    /*shared_array提供operator[]操做符重載,能夠像普通數組同樣訪問元素*/
    /*沒有*和->操做符重載,由於shared_array持有的不是一個普通指針*/
    /*析構函數使用delete[]釋放資源,而不是delete*/
    int* ip = new int[100];
    shared_array<int> sar(ip);
    shared_array<int> sar1 = sar;
    sar[0]=10;  //shared_array不提供數組索引的範圍檢查
    cout<<"sa[0]="<<sar[0]<<",sar1[0]="<<sar1[0]<<endl;
    /*shared_array能夠用shared_ptr<std::vector>或者std::vector<shared_ptr>來代替*/

    /*week_ptr*/
    /*weak_ptr是配合shared_ptr而引入的一種智能指針,沒有重載operator*和->*/
    /*weak_ptr充當一個觀察者,觀察指針的引用計數,在構造和析構的時不會引發引用計數的變化*/
shared_ptr<int> spp(new int(10)); cout<<"該指針的引用計數:"<<spp.use_count()<<endl; weak_ptr<int> wp(spp);          //從shared_ptr建立weak_ptr cout<<"該指針的引用計數:"<<wp.use_count()<<endl; if(!wp.expired())          //判斷week_ptr觀察的對象是否失效 { shared_ptr<int> spp1 = wp.lock(); //得到一個shared_ptr *spp1 = 100; cout<<"該指針的引用計數:"<<wp.use_count()<<endl; } cout<<"該指針的引用計數:"<<wp.use_count()<<endl; wp.reset(); //if(!wp) cout<<"該指針無效"<<endl; 沒有重載!操做符 if(wp.expired()) cout<<"該指針無效"<<endl; if(!wp.lock()) cout<<"獲取指針失敗"<<endl; /*week_ptr的的一個重要用途就是得到this指針的shared_ptr,使對象本身可以生產shared_ptr管理本身*/ shared_ptr<self_shared> ssp = make_shared<self_shared>(314); ssp->print(); shared_ptr<self_shared> ssp1 = ssp->shared_from_this(); ssp1->x=1000; ssp1->print(); //警告:不能從一個普通的對象(非shared_ptr)使用shared_from_this()獲取shared_ptr,例如: //self_shared ss; //shared_ptr<self_shared> ssp3 = ss.shared_from_this(); /*以上語法上沒問題,能夠編譯經過,但在運行時致使shared_ptr析構時企圖刪除一個棧上分配的對象,發生未定義行爲*/ }

   pool庫是Boost程序庫在內存管理方面提供的另外一個有用的工具,它實現了高效的內存池,用於管理內存資源。pool提供了pool、object_pool、singleton_pool、pool_alloc四種形式的內存池。算法

struct demo_class
{
public:
    int a,b,c;
    demo_class(int x=1,int y=2,int z=3) : a(x),b(y),c(z){}
};
typedef singleton_pool<demo_class,sizeof(int)> sp1; //第一個參數僅僅做爲標記,第二個參數每次分配的內存塊大小
void pool_test()
{
    /*boost.pool庫基於簡單分隔存儲思想實現了一個快速緊湊的內存池庫,
     * 不只可以管理大量的對象的分配/釋放小對象頗有效,並且不須要delete
     * pool庫包括四個組成部分:最簡單的pool,分配類實例的 object_pool,
     * 單件內存池singleton_pool和可用標準庫pool_alloc*/
    pool<> p1(sizeof(int));  //使用默認分配器分配一個可分配的int的內存池 sizeof(int)爲一次欲分配的內存塊大小
    int * p = (int*)p1.malloc(); //須要把void*轉換爲須要的類型
    if(p1.is_from(p)) cout<<"是從該pool分配的內存"<<endl;
    p1.free(p);  //釋放內存池分配的內存快
    for(int i=0;i<100;i++)  //連續分配大量的內存
    {
        p1.ordered_malloc(10); //該函數分配的同時合併空閒快鏈表
    }

    /*object_pool使用於類實例的內存池,它的功能與pool相似,但在析構時對全部已經分配的內存快調用析構函數*/
    object_pool<demo_class> p2; //對象對象內存池

    demo_class* dp = (demo_class*)p1.malloc();
    if(p2.is_from(dp)) cout<<"從該內存池分配的內存"<<endl;
    //p指向的內存未通過初始化
    cout<<dp->a<<","<<dp->b<<","<<dp->c<<endl;

    dp = p2.construct(7,8,9);  //構造一個對象,能夠傳遞參數
    cout<<dp->a<<","<<dp->b<<","<<dp->c<<endl;
    object_pool<string> pls;  //定義一個分配string對象的內存池
    for(int i=0;i<10;i++)  //連續分配大量的string對象
    {
        string * ps = pls.construct("hello object_pool");
        cout<<*ps<<endl;
    }
    /*singleton_pool是一個單件內存池,不須要聲明singleton_pool實例,直接用::來調用靜態成員函數*/
    int * pi1 = (int*) sp1::malloc();
    if(sp1::is_from(pi1)) cout<<"是該內存池分配的內存"<<endl;
    sp1::release_memory();

    /*pool_alloc提供了兩個能夠用於標準容器模板參數的內存分配器,
     * 分別是pool_alloc和fast_pool_allocator,除了有特別的需求,
     * 咱們應該老是使用STL實現自帶的內存分配器,使用pool_alloc須要通過仔細的測試,以保證它與容器共同工做
     * */
    vector<int,pool_allocator<int> > v;
    v.push_back(10);
    cout<<v.size()<<v[0]<<endl;
}
相關文章
相關標籤/搜索