詳細C ++ 11のスマートポインタ

序文

4 C ++スマートポインタ内部:auto_ptrは、unique_ptrを、shared_ptrの、weak_ptrを3がC ++で、11をサポート11と第1は、C ++を放棄してきました。

C ++ 11には、スマートポインタを紹介します

主に割り当てられたヒープメモリを管理するために使用されるスマートポインタ、それは一般的なパッケージスタックポインタオブジェクトです。ときにオブジェクトのスタックのライフサイクルの終わりには、アプリケーションは、メモリリークを防ぐために、メモリ・デストラクタで解放されます。C ++ 11、最も一般的に使用される参照カウント法を使用shared_ptrのスマートポインタ型であり、現在のレコード番号が参照されるメモリリソーススマートポインタ。参照カウントは、ヒープメモリ上に割り当てられています。参照カウントが満了したときにプラス1、ときに、新しい1参照カウントをデクリメントします。参照カウントが0の場合のみ、スマートポインタは自動的にメモリリソース参照を解放します。ポインタとしてスマートポインタをshared_ptrのように直接初期化するときは、クラスがあり、通常のポインタを割り当てることはできません。これは、コンストラクタまたは関数をmake_shared通常のポインタを通過させることができます。そして、通常のポインタget関数によって得ることができます。

なぜスマートポインタを使用します

このような場合があるので、スマートポインタの役割は、ポインタ管理である:スペースアプリケーションは、メモリリークが生じる、機能の終了時に解放することを忘れ。スマートポインタがクラスであるため、クラスは、そのクラスの範囲を超えているときに自動的にデストラクタを呼び出します、主にこの問題を回避することができますスマートポインタを使用して、デストラクタが自動的にリソースを解放します。だから、スマートポインタの原則の役割が自動的に手動でメモリ空間を解放することなく、関数の最後にメモリ領域を解放です。

auto_ptrは

専有モードを使用して(C ++ 98回のプログラムは、C ++ 11は放棄しています)。

auto_ptr<string> p1 (new string ("I reigned lonely as a cloud.”)); 
auto_ptr<string> p2; 
p2 = p1; //auto_ptr不会报错.

この時点で、プログラムの実行時に、P1、P1が、アクセスの所有権を奪わP2がスローされます、文句はありません。だから、auto_ptrは欠点がある:潜在的なメモリ破損の問題があります!

unique_ptrを

一つだけのスマートポインタが同じ時間でオブジェクトを指すことができることを確認し、(auto_ptrは交換)unique_ptrを厳密に排他的な概念を所有しているか、持って実装。(「例外が発生したため、新しいオブジェクトを作成した後、削除を呼び出すことを忘れ」、など)リソースリークを避けるために不可欠である特に便利です。

上記所有パターンの使用例、または

unique_ptr<string> p3 (new string ("auto"));   //#4
unique_ptr<string> p4;                       //#5
p4 = p3;//此时会报错!!

コンパイラは、有効なデータに問題P3もはやポイントを避け、P4 = P3違法だと思います。あなたはP3をコピーしようとすると、それはコンパイルエラーになる、とのauto_ptrは、実行時に隠された危険を埋めエラーをコンパイルすることができます。そのため、auto_ptrはより安全unique_ptrを。

またunique_ptrをよりスマートな場所があります。プログラムは、ソースが正しい値unique_ptrを一時的なものであれば、他に割り当てられunique_ptrをしようとすると、そうすることを許され、コンパイラ、いくつかの時間のために存在しますunique_ptrを元に、コンパイラが禁止される場合がそうすることが、例えば:

unique_ptr<string> pu1(new string ("hello world")); 
unique_ptr<string> pu2; 
pu2 = pu1;                                      // #1 不允许
unique_ptr<string> pu3; 
pu3 = unique_ptr<string>(new string ("You"));   // #2 允许

どこ#1は害につながる可能性がぶら下がっunique_ptrを(PU1)を、左。それはコンストラクタunique_ptrを呼んでいるようと#2は、unique_ptrををぶら下げ残していないが、コンストラクタは一時オブジェクトがPU3を与える所有権の後に破棄されます作成されます。auto_ptrは2つの代入を許可するよりもunique_ptrをショーでの動作とこのような状況、。

注:あなたは本当に、このようなポインタが新しい値に割り当てることができます再利用を確保するために、#1と同様の操作を実行します。標準C ++ライブラリの関数はstd ::動きは()があり、あなたがunique_ptrを別のものを割り当てることができます。所有権の移転にもかかわらず、元の状況ポインタ通話することも可能です(崩壊の呼び出し)が表示されます。しかし、文法は、あなたが明確に彼らが何をしているか知っているように、混乱の元ポインタを起動しないように、所有権の移転を強調することができます。

エクストラ:ブースト:: scoped_ptrをBoostライブラリは、排他的なスマートポインタですが、それは最初から所有権の移転と終わりがリソースに対してのみ責任を負うことはできません、それはより慎重安全なだけでなく、アプリケーションの狭い範囲です。)

例えば:

unique_ptr<string> ps1, ps2;
ps1 = demo("hello");
ps2 = move(ps1);
ps1 = demo("alexia");
cout << *ps2 << *ps1 << endl;

shared_ptrの

shared_ptrの共有概念を実現しなければなりません。複数のスマートポインタが同じオブジェクトを指すことができますし、リリースしたときにそれに関連するリソースは、「最後の参照を破壊する」だろう。シェアは、リソースの名前からも分かるリソースは、いくつかのポインタを共有していることを示すためにカウント機構を使用して、複数のポインタで共有することができます。あなたはメンバ関数はuse_countによってリソースの所有者の数を見ることができます()。新しいことによって構築することに加えて、auto_ptrは、unique_ptrを、weak_ptrを渡すことによって構築することができます。我々は)(解放するために呼び出すと、現在のポインタが1によってカウント、リソースの所有権を解放します。カウントが0に等しい場合、リソースが解放されます。

shared_ptrのは、オブジェクトのauto_ptrを所有権の制限に対処することである(auto_ptrは排他的である)、メカニズム参照カウントを使用するに所有権を共有するスマートポインタを提供します。

メンバ関数:

参照カウントはuse_countの数を返します。

排他的な所有者かどうかのユニークな戻り値(はuse_count 1)

スワップのための2つのshared_ptrオブジェクト(交換が所有する、すなわち、オブジェクト)

それは、元のオブジェクトの参照カウントが発生します、変更されたオブジェクトまたはオブジェクトの所有権を放棄する内部リセットを削減

彼らは重い負荷()メソッドを持っており、オブジェクトのように直接使用が同じであるため、内部のGETオブジェクト(ポインタ)を返します。

shared_ptr<int> sp(new int(1)); 

SPとsp.getは()と同等です。

簡単な例をshare_ptr:

int main()
{
    string *s1 = new string("s1");

    shared_ptr<string> ps1(s1);
    shared_ptr<string> ps2;
    ps2 = ps1;

    cout << ps1.use_count()<<endl;  //2
    cout<<ps2.use_count()<<endl;    //2
    cout << ps1.unique()<<endl; //0

    string *s3 = new string("s3");
    shared_ptr<string> ps3(s3);

    cout << (ps1.get()) << endl;    //033AEB48
    cout << ps3.get() << endl;  //033B2C50
    swap(ps1, ps3); //交换所拥有的对象
    cout << (ps1.get())<<endl;  //033B2C50
    cout << ps3.get() << endl;  //033AEB48

    cout << ps1.use_count()<<endl;  //1
    cout << ps2.use_count() << endl;    //2
    ps2 = ps1;
    cout << ps1.use_count()<<endl;  //2
    cout << ps2.use_count() << endl;    //2
    ps1.reset();    //放弃ps1的拥有权,引用计数的减少
    cout << ps1.use_count()<<endl;  //0
    cout << ps2.use_count()<<endl;  //1
}

weak_ptrを

それはよく使わが、一つのshare_ptrスマートポインタしてきたがshare_ptrはまだお互いにshared_ptrのメンバ変数ポインティングを使用して、相互に2つのオブジェクトが、メモリリークが生じる、循環参照の参照カウントの障害をもたらす場合、メモリリークのケースを持っています。

weak_ptrを制御していない、それはshared_ptrの管理するオブジェクトを指し示す、スマートポインタオブジェクトのライフサイクルである。強いのshared_ptrによって参照されているオブジェクトのメモリ管理、唯一の管理対象オブジェクトへのアクセス手段を提供するのweak_ptr。スマートポインタを使用して設計のweak_ptr目的はshared_ptrのshared_ptrの作業を支援するために導入され、それだけでその構造とデストラクタは、基準マークまたは縮小の数の増加を引き起こすことはありません、どちらか一方のweak_ptr shared_ptrのオブジェクトの構築に由来することができます。weak_ptrをshared_ptrのががお互いを参照するときに、2つが相互に参照するshared_ptrの場合、デッドロックを解決するために使用され、2つのポインタの参照カウントが0に低下することはありません、リソースが解放されることはありません。それは弱参照オブジェクトであり、オブジェクトの間の参照カウントを増加させず、お互いのshared_ptrに変換することができる、のshared_ptrがそれに直接割り当てることができ、それはshared_ptrのロック機能を呼び出すことによって得ることができます。

class B;    //声明
class A
{
public:
    shared_ptr<B> pb_;
    ~A()
    {
        cout << "A delete\n";
    }
};

class B
{
public:
    shared_ptr<A> pa_;
    ~B()
    {
        cout << "B delete\n";
    }
};

void fun()
{
    shared_ptr<B> pb(new B());
    shared_ptr<A> pa(new A());
    cout << pb.use_count() << endl; //1
    cout << pa.use_count() << endl; //1
    pb->pa_ = pa;
    pa->pb_ = pb;
    cout << pb.use_count() << endl; //2
    cout << pa.use_count() << endl; //2
}

int main()
{
    fun();
    return 0;
}

、2つのリソース参照カウントが2で、関数へのジャンプ、スマートポインタPA、2つのリソース参照カウントを1減らすPBのデストラクタが、が、両方の引用互いにPBへの参照を楽しい機能のPAを参照してください。またはリソースを生じる1つのカウントは、解放されないため(、Bが呼び出されるデストラクタはない)メモリリークが生じる、機能結果デストラクタコンテンツ出力が不足していません。1の代わりにそれにweak_ptrをした場合、我々は、クラス内のshared_ptr pb_を置く代わりにpb_のweak_ptr、結果は次のとおりです。

1
1
1
2
B delete
A delete

この場合、参照リソースBのPbデストラクタは、カウント値がB 0になったときに1が起動のみ、Bが解放され、また一方ときデストラクタPA、Bの放出マイナス1のカウントを行います1でカウント、カウントAは、Aが解除され、0です。

注:我々は、このような方法でプリント()のようなオブジェクト・メソッド、オブジェクトBへの直接アクセスをweak_ptrをすることができないので、我々は、PA-> PB _->印刷(アクセスできない ) pb_のweak_ptrをので、それがすべき最初の変換shared_ptrのよう、のような:

shared_ptr<B> p = pa->pb_.lock();
p->print();

コアshare_ptrと実装のweak_ptr

カウンタの実現とカウンタshare_ptrクラスの割り当て、構成、および第1のカウンタshare_ptrに依存弱参照ポインタとしてweakptr

カウンター単純な実装

class Counter
{
public:
    Counter() : s(0), w(0){};
    int s;  //share_ptr的引用计数
    int w;  //weak_ptr的引用计数
};

オブジェクトカウンタにヘッドベース基準を維持するためにメモリの一部を適用するために使用され、sはshare_ptr参照カウントされ、参照カウントがWのweak_ptrをある、wは0である場合、オブジェクトはカウンタを削除します。

share_ptrの簡単な実装

template <class T>
class WeakPtr; //为了用weak_ptr的lock(),来生成share_ptr用,需要拷贝构造用

template <class T>
class SharePtr
{
public:
    SharePtr(T *p = 0) : _ptr(p)
    {
        cnt = new Counter();
        if (p)
            cnt->s = 1;
        cout << "in construct " << cnt->s << endl;
    }
    ~SharePtr()
    {
        release();
    }

    SharePtr(SharePtr<T> const &s)
    {
        cout << "in copy con" << endl;
        _ptr = s._ptr;
        (s.cnt)->s++;
        cout << "copy construct" << (s.cnt)->s << endl;
        cnt = s.cnt;
    }
    SharePtr(WeakPtr<T> const &w) //为了用weak_ptr的lock(),来生成share_ptr用,需要拷贝构造用
    {
        cout << "in w copy con " << endl;
        _ptr = w._ptr;
        (w.cnt)->s++;
        cout << "copy w  construct" << (w.cnt)->s << endl;
        cnt = w.cnt;
    }
    SharePtr<T> &operator=(SharePtr<T> &s)
    {
        if (this != &s)
        {
            release();
            (s.cnt)->s++;
            cout << "assign construct " << (s.cnt)->s << endl;
            cnt = s.cnt;
            _ptr = s._ptr;
        }
        return *this;
    }
    T &operator*()
    {
        return *_ptr;
    }
    T *operator->()
    {
        return _ptr;
    }
    friend class WeakPtr<T>; //方便weak_ptr与share_ptr设置引用计数和赋值

protected:
    void release()
    {
        cnt->s--;
        cout << "release " << cnt->s << endl;
        if (cnt->s < 1)
        {
            delete _ptr;
            if (cnt->w < 1)
            {
                delete cnt;
                cnt = NULL;
            }
        }
    }

private:
    T *_ptr;
    Counter *cnt;
};

、構成のコピーコンストラクタ、代入デリファレンス、リリースによると_ptrメモリcntが0時に参照カウントで削除します。Share_ptrはとしての機能インタフェースを与えられました。

単純な実装のweak_ptr

template <class T>
class WeakPtr
{
public: //给出默认构造和拷贝构造,其中拷贝构造不能有从原始指针进行构造
    WeakPtr()
    {
        _ptr = 0;
        cnt = 0;
    }
    WeakPtr(SharePtr<T> &s) : _ptr(s._ptr), cnt(s.cnt)
    {
        cout << "w con s" << endl;
        cnt->w++;
    }
    WeakPtr(WeakPtr<T> &w) : _ptr(w._ptr), cnt(w.cnt)
    {
        cnt->w++;
    }
    ~WeakPtr()
    {
        release();
    }
    WeakPtr<T> &operator=(WeakPtr<T> &w)
    {
        if (this != &w)
        {
            release();
            cnt = w.cnt;
            cnt->w++;
            _ptr = w._ptr;
        }
        return *this;
    }
    WeakPtr<T> &operator=(SharePtr<T> &s)
    {
        cout << "w = s" << endl;
        release();
        cnt = s.cnt;
        cnt->w++;
        _ptr = s._ptr;
        return *this;
    }
    SharePtr<T> lock()
    {
        return SharePtr<T>(*this);
    }
    bool expired()
    {
        if (cnt)
        {
            if (cnt->s > 0)
            {
                cout << "empty " << cnt->s << endl;
                return false;
            }
        }
        return true;
    }
    friend class SharePtr<T>; //方便weak_ptr与share_ptr设置引用计数和赋值
    
protected:
    void release()
    {
        if (cnt)
        {
            cnt->w--;
            cout << "weakptr release" << cnt->w << endl;
            if (cnt->w < 1 && cnt->s < 1)
            {
                //delete cnt;
                cnt = NULL;
            }
        }
    }

private:
        T *_ptr;
    Counter *cnt;
};

一般share_ptrで構成のweak_ptrは、オリジナル関数ポインタが空でチェックすることにより有効期限が切れ、share_ptrに変換ロック。

おすすめ

転載: www.cnblogs.com/WindSun/p/11444429.html