C++11スマートポインタ

6834 ワード

C++11スマートポインタ
スマートポインタを使用する理由:
インテリジェントポインタの役割は、関数の終了時に申請されたスペースが解放され忘れ、メモリが漏洩するため、ポインタを管理することです.インテリジェントポインタを使用すると、この問題を大幅に回避できます.インテリジェントポインタはクラスであり、クラスの役割ドメインを超えた場合、クラスは自動的に構造関数を呼び出し、構造関数は自動的にリソースを解放します.したがって、スマートポインタの機能原理は、関数の終了時にメモリ領域を自動的に解放し、手動でメモリ領域を解放する必要がないことです.
1.auto_ptr(c++98のスキーム、cpp 11はすでに捨てられた)
所有権モードの使用
auto_ptr< string> p1 (new string ("I reigned lonely as a cloud.”));
auto_ptr p2;
p2 = p1; //auto_ptr    .

この場合、p 2はp 1の所有権を剥奪することはないが、プログラムが実行されるとp 1にアクセスするとエラーが発生する.だからauto_ptrの欠点は、潜在的なメモリクラッシュの問題があることです.
2.unique_ptr(auto_ptrの置き換え)
unique_ptrは、同じ時間に1つのスマートポインタだけがオブジェクトを指すことを保証する独占的な所有または厳格な所有概念を実現する.「newでオブジェクトを作成した後、異常が発生したためdeleteを呼び出すのを忘れた」など、リソースの漏洩を回避するのに特に役立ちます.
所有権モデルを採用するか、それとも上の例を採用するか.
unique_ptr p3 (new string ("auto"));   //#4
unique_ptr p4;                       //#5
p4 = p3;//     !!

コンパイラはp 4=p 3が不正であると考え,p 3が有効なデータを指さないという問題を回避した.したがってunique_ptr比auto_ptrの方が安全です.
さらにunique_ptrにはもっと賢いところがあります.プログラムがuniqueをしようとするとptrが別の値に割り当てられた場合、ソースunique_ptrは一時的な右値であり、コンパイラはそれを許可します.ソースunique_ptrはしばらく存在し、コンパイラは次のように禁止されます.
unique_ptr pu1(new string ("hello world"));
unique_ptr pu2;
pu2 = pu1;                                      // #1 not allowed
unique_ptr pu3;
pu3 = unique_ptr(new string ("You"));   // #2 allowed

その中に#1がぶら下がったuniqueを残すptr(pu 1)は、危害を及ぼす可能性がある.#2はぶら下がったuniqueを残さないptrはunique_を呼び出すためptrのコンストラクション関数.このコンストラクション関数で作成された一時オブジェクトは、pu 3に所有権を譲ると破棄されます.このような状況に従う行為はunique_ptrは、2つの付与を許可するauto_よりも優れている.ptr .
unique_ptr ps1(new string ("hello world"));
unique_ptr ps2;
ps2 = move(ps1);
ps1 = unique_ptr(new string ("You"));
cout << *ps2 <


3.shared_ptr
  • は、同じポインタpを管理し、1つの管理カウントnによって統計することができ、nが0である場合、最後のshared_ptrオブジェクトが管理対象に接触すると、pポインタはdeleteと構造関数を自動的に呼び出します.
  • 動的に割り当てられたオブジェクトポインタのみがshared_に渡されます.ptrオブジェクトは管理され、通常の遍歴、グローバル変数のポインタは管理できません.構造関数がないためです.
  • 管理時2番目shared_ptrオブジェクトは、すでに管理されているshared_を通過する必要があります.ptrオブジェクトは、同じポインタを管理します.

  • newで動的に割り当てられたメモリ領域がプログラムの各実行パスで解放されることを確保するのは面倒なことです.C++11テンプレートライブラリのヘッダファイルに定義されたスマートポインタ、すなわちshared_ptrテンプレートは、この問題を部分的に解決するために使用されます.
    new演算子が返すポインタpをshared_に渡す限りptrオブジェクト「ホスティング」は、delete p文をどこで書くか心配する必要はありません.実際には、この文を書く必要はありません.ホスティングpのshared_ptrオブジェクトは、消滅時にdelete pを自動的に実行します.そして、このshared_ptrオブジェクトはポインタpのように使用できます.すなわち、pを管理するshared_を仮定します.ptrオブジェクトをptrと呼びます.*ptrはpが指すオブジェクトです.
    shared_を通してptrの構造関数はshared_ptrオブジェクトは、new演算子が返すポインタを管理します.書き方は次のとおりです.
    shared_ptr ptr(new T);  // T     int、char、      
    

    その後、ptrはT*タイプのポインタのように使用できます.すなわち、*ptrはnewで動的に割り当てられたオブジェクトです.
    複数shared_ptrオブジェクトは、1つのポインタpを共に管理することができ、pを管理したshared_がすべてptrオブジェクトがすべて管理を解除すると、delete pが実行されます.
    #include 
    #include 
    using namespace std;
    class A
    {
    public:
        int i;
        A(int n):i(n) { };
        ~A() { cout << i << " " << "destructed" << endl; }
    };
    int main()
    {
        shared_ptrsp1(new A(2)); //A(2)はsp 1によって  され、
    shared_ptrsp2(sp1);       //A(2)sp 2による    
    shared_ptrsp3;
    sp3 = sp2;   //A(2)sp 3による    
    cout << sp1->i << "," << sp2->i <i << endl;
    A * p = sp3.get();      // getは  されたポインタを し,pはA(2)を す.
    cout << p->i << endl;  //  2
    sp1.reset(new A(3));    // resetは しいポインタを  し、sp 1はA(3)を  する。
    sp2.reset(new A(4));    // sp 2ホスティングA(4)
    cout << sp1->i << endl; //  3
    sp3.reset(new A(5));    // sp 3  A(5),A(2)    ,delete
    cout << "end" << endl;
    return 0;
    }

    プログラムの出力結果は以下の通りである:2,2,2 3 2 destructed end 5 destructed 4 destructed 3 destructed
    複数のshareclptrオブジェクトは、14行目および16行目の形式で同じポインタを管理することができる.複数のshared_ptrオブジェクトは、共通の管理ポインタに対する「管理カウント」を共有します.n個shared_ptrオブジェクトが同じポインタpを管理すると、pの管理カウントはnとなる.ポインタの管理カウントが0に減少すると、ポインタは解放されます.shared_ptrオブジェクトが消滅したり、新しいポインタが管理されたりすると、元の管理ポインタの管理カウントが1減少します.
    20、21行目shared_ptrのresetメンバー関数は、オブジェクトが元の管理ポインタの管理を解除し(もしあれば)、新しいポインタを管理することができる.元のポインタの管理カウントは1減少します.
    出力の4行目はnewで作成した動的オブジェクトA(2)が解放されたことを示す.プログラムにdelete文が書かれておらず、A(2)が解放されたのは、プログラムの23行目が実行された後、shared_ptrオブジェクトはA(2)を管理し,A(2)の管理カウントは0になる.最後のA(2)管理解除shared_ptrオブジェクトはA(2)を解放します.
    main関数が終了すると、sp 1、sp 2、sp 3オブジェクトが消滅し、それぞれが管理するポインタの管理カウントを0に減らし、その管理するポインタを解放すると、5 destructed 4 destructed 3 destructed
    shared_に渡すには、動的に割り当てられたオブジェクトへのポインタのみです.ptrオブジェクト管理.通常のローカル変数、グローバル変数へのポインタをshared_に渡します.ptrは管理されており、コンパイル時に問題はありませんが、プログラムの実行時にエラーが発生します.動的に割り当てられたメモリ領域を指さないポインタは構築できません.
    2つのshared_を次のようにすることはできません.ptrオブジェクトは同じポインタを管理します(2番目のshared_ptrオブジェクトは、すでに管理されているshared_ptrオブジェクトを介して同じポインタを管理する必要があります):
    A* p = new A(10);
    shared_ptr sp1(p), sp2(p);

    sp 1とsp 2は、同じp対のホスティングカウントを共有するのではなく、それぞれp対のホスティングカウントを1として記す(sp 2はpがsp 1にホスティングされていることを知らない).このように、sp 1が消滅するとpが析出し、sp 2が消滅するとpが再析出し、プログラムがクラッシュする.
    4.weak_ptr
  • shared_を解決するために使用ptr相互参照によるデッドロック
  • weak_ptrはオブジェクトに直接アクセスできません.shared_にlock()関数で値を割り当てる必要があります.ptr、次にオブジェクト
  • にアクセス
    weak_ptrは、shared_を指すオブジェクトのライフサイクルを制御しないスマートポインタです.ptrが管理するオブジェクト.そのオブジェクトのメモリ管理を行うのはその強い参照のshared_ptr. weak_ptrは、管理オブジェクトへのアクセス手段を提供するだけです.weak_ptr設計の目的はshared_に合わせることですptrが導入したスマートポインタはshared_を支援するptrは1つのsharedからのみ動作します.ptrまたは別のweak_ptrオブジェクト構造は、参照記数の増加または減少を引き起こさない構造および析出構造である.weak_ptrはshared_を解決するために使用されますptr相互参照時のデッドロック問題、2つのshared_ptrが互いに参照すると、この2つのポインタの参照カウントは永遠に0に下がることができず、リソースは永遠に解放されません.オブジェクトへの弱い参照です.オブジェクトの参照数とshared_は増加しません.ptr間は互いに変換できるshared_ptrは直接値を割り当てることができ、lock関数を呼び出すことでshared_を得ることができる.ptr.
    class B;
    class A
    {
    public:
    shared_ptr pb_;
    ~A()
    {
    cout< pa_;
    ~B()
    {
    cout< pb(new B());
    shared_ptrpa(new A());
    pb->pa_ = pa;
    pa->pb_ = pb;
    cout<

    fun関数ではpa,pbが相互に参照され,2つのリソースの参照カウントが2であり,関数をスキップしようとするとスマートポインタpa,pbが解析されると2つのリソースの参照カウントが1つ減少するが,両者の参照カウントは1であり,関数をスキップするとリソースが解放されない(A Bの構造関数は呼び出されていない),そのうちの1つをweak_に変更するとptrでいいです.クラスAのshared_をptr pb_; weak_に変更ptr pb_; 実行結果は以下の通りである.このようにすると、リソースBの参照開始は1のみであり、pbプロファイルの場合、Bのカウントが0になり、Bが解放され、Bが解放されると同時にAのカウントが1減少し、paプロファイルの場合、Aのカウントが1減少すると、Aのカウントが0になり、Aが解放される.
    私たちがweakを通過できないことに注意してください.ptrがオブジェクトに直接アクセスする方法、例えばBオブジェクトにprint()という方法があります.pa->pb_->にはアクセスできません.print(); 英語pb_weakですptr、まずsharedに変換すべきだ.ptr、例:shared_ptr p = pa->pb_.lock(); p->print();