条項13:対象として資源を管理する

8561 ワード

資源とは、いったんそれを使ったら、将来システムに返さなければならないということです.C++で最もよく使われるリソースは、動的にメモリを割り当てることです(メモリが割り当てられているのに解放されないと、メモリが漏洩する可能性があります).ただし、メモリは管理する必要がある多くのリソースの1つにすぎません.他の一般的なリソースには、ファイルディスクリプタ(file descriptors)、反発ロック(mutex locks)、グラフィックインタフェースのフォントとブラシ、データベース接続、およびネットワークsocketsも含まれます.いずれのリソースも、使用しない場合はシステムに返さなければならないことが重要です.
株式、債券などの投資行動をシミュレートするためのライブラリを使用すると、root class Investmentから様々な投資タイプが継承されます.
class Investment

{

 ...     //"    "       root class

};


さらに、このライブラリは、工場関数を介して特定のInvestmentオブジェクトを供給すると仮定します.
Investment* createInvestment();   //    ,  Investment            。         。
                    // ,

createInvestmentが返すリソースが常に解放されることを保証するために、リソースをオブジェクト内に配置すると、C++の「構造関数自動呼び出しメカニズム」に依存してリソースが解放されることを保証できます.
多くのリソースはheapスタック内に動的に割り当てられ、単一のブロックまたは関数内に使用される.これらは、制御フローがそのブロックまたは関数から離れるときに解放されるべきである.標準ライブラリで提供されるauto_ptrはこのような形式に対して設計された特製製品である.auto_ptrは「クラスポインタ(pointer-like)オブジェクト」、すなわちいわゆる「スマートポインタ」であり、その構造関数は、その指すオブジェクトに対してdeleteを自動的に呼び出す.次はauto_の使用方法を示します.ptrは、f関数の潜在的なリソース漏洩の可能性を回避するために:
void f()

{

  std::auto_ptr<investment> pInv(createInvestment());   //     
...                              // pInv
                                // auto_ptr pInv
}

この簡単な例では、「オブジェクトでリソースを管理する」という2つの重要な考え方を示します.
1、資源を獲得するか、すぐに管理対象(managing object)に入れる.以上のコードのcreateInvestmentから返されるリソースは、その管理者auto_として扱われます.ptrの初期値.実際、「オブジェクトでリソースを管理する」という考え方は、リソースを取得するタイミングが初期化のタイミング(ResourceAcquisition Is Initialization;RAI)となることが多い.なぜなら、ほとんどの場合、リソースを取得した後、同じ文内で管理オブジェクトを初期化するからである.
2、管理対象(managing object)は構造関数を用いて資源が解放されることを確保する.制御フローがブロックからどのように離れるかにかかわらず、オブジェクトが破棄されると(例えば、オブジェクトが役割ドメインから離れると)、その構造関数は自然に自動的に呼び出され、リソースが解放されます.
注意:auto_のためptrが破棄されると自動的に削除されるので、複数のauto_ptrは同時に同じオブジェクトを指します.そうでなければ、オブジェクトが1回以上削除されると、「未定義の動作」というエラーが発生します.この問題を予防するためにauto_ptrには特殊な性質があります.copyコンストラクション関数またはcopy assignmentオペレータでコピーするとnullになり、コピーしたポインタはリソースの唯一の所有権を取得します.
std::auto_ptr<Investment> pInv1(CreateInvestment());   //pInv1  CreateInvestment   
std::auto_ptr<investment> pInv2(pInv1); // pInv2 ,pInv1 null
pInv1 = pInv2;                        // pInv1 ,pInv2 null

auto_ptrの代替案は「カウント型スマートポインタを参照」(reference-counting smart pointer;RCSP)である.RCSPとは、あるリソースを指すオブジェクトの数を追跡し続け、誰も指さしていないときに自動的に削除するスマートポインタでもあります.RCSPは、RCSPがリングリファレンス(cycles of reference、例えば、実際に使用されていない2つのオブジェクトが互いに指し合っているため、まだ「使用されている」状態にあるように見える)を破ることができない動作タイプのゴミ回収を提供する.
TR 1のtr 1::shared_ptr(条項54参照)はRCSPなので、fと書くことができます.
void Func()

{

   ...

   std::tr1::shared_ptr<Investment> pInv1(createInvestment());  //pInv1  crateInvestment   



   std::tr1::shared_ptr<Investment> pInv2(pInv1);         //pInv1 pInv2       



   pInv1 = pInv2;                           //  ,     

  ...

} //     ,pInv1 pInv2   ,             


なぜならptrは完璧ではありません.確かに便利ですが、欠陥もあります.使用するときは避けるように注意してください.まず、auto_をptrオブジェクトはSTLコンテナの要素として使用されます.C++標準では、このようなことは明確に禁止されています.そうしないと、予見できない結果に遭遇する可能性があります.
auto_ptrとtr 1::shared_ptrの両方は、delete[]ではなく、その解析関数内でdelete[]動作を行います.動的に割り当てられた配列にauto_を使用することはできませんptrまたはtr 1::shared_ptr.例:
std::auto_ptr<std::string> aps(new std::string[10]);	//  !      delete  


std::tr1::shared_ptr<int> spi(new int[1024]); // ! delete

覚えておいてください:
1.メモリの漏洩を防ぐために、RAIIオブジェクトを使用して、コンストラクション関数でリソースを取得し、コンストラクション関数でリソースを解放します.
2、よく使われるRAI classはそれぞれtrl 1::shared_ptrとauto_ptr.trl1::shared_ptrは通常、copy挙動が直感的であるため、より好ましい選択である.Auto_を選択するとptr,コピー動作は被コピー物をnullに向ける.trl1::shared_ptrはヘッダファイルにあります
そしてauto_について集めましたptrのいくつかの注意事項:1、auto_ptrは所有権を共有できません.2、auto_ptrは配列3、auto_を指すことができないptrはコンテナのメンバーとして使用できません.4、付与操作でauto_を初期化できないptrstd::auto_ptr p(new int(42));    //OKstd::auto_ptr p = new int(42);   //ERRORこれはauto_ptrのコンストラクション関数はexplicit 5として定義され、auto_ptr容器に入れる
そして筆者がおすすめしたのはboostのshared_ptr、そしてshared_を見終わったptrスマートポインタについての紹介と例.5種類auto_ptrが不足しているポインタは、新しいコードをテストするのと同じドキュメントを表示できることを詳細に理解する必要があります.
scoped_ptr
<boost/scoped_ptr.hpp>
単純な単一オブジェクトの一意の所有権.コピー不可.
scoped_array
<boost/scoped_array.hpp>
単純な配列の一意の所有権.コピー不可.
shared_ptr
<boost/shared_ptr.hpp>
複数のポインタ間で共有されるオブジェクトの所有権.
shared_array
<boost/shared_array.hpp>
複数のポインタ間で共有される配列所有権.
weak_ptr
<boost/weak_ptr.hpp>
1つの所属 shared_ptr のオブジェクトの所有権のないオブザーバー.
intrusive_ptr
<boost/intrusive_ptr.hpp>
侵入参照カウントを持つオブジェクトの共有所有権.
1. shared_ptrはBoostライブラリが提供するスマートポインタの実装であり、shared_ptrはauto_を解決するためですptrのオブジェクト所有権の限界(auto_ptrは排他的)は、参照カウントを使用するメカニズムで所有権を共有できるスマートポインタを提供します.2. shared_ptr比auto_ptrの方が安全3.shared_ptrはコピーおよび付与可能であり、コピー動作も等価であり、比較可能であり、これは、標準ライブラリの一般的なコンテナ(vector,list)および関連コンテナ(map)に入れることができることを意味する.