【Effective c++】条項13:対象管理リソース

8010 ワード

資源とは、いったん使ったら、将来システムに返さなければならないということです.
 
様々な投資タイプがroot class Investmentから継承される、モールド投資動作用のライブラリを使用するとします.

  
  
  
  
  1. class Investment{...};//root class 

さらに、このライブラリは、工場関数を使用して特定のInvestmentオブジェクトを提供すると仮定します.

  
  
  
  
  1. Investment* createInvestment();// , Investment  
  2.                                // 。 。 
  3.                                // ,  

createInvestmentの呼び出し側が返されたオブジェクトを使用した場合、削除する責任があります.

  
  
  
  
  1. void f() 
  2.   Investment* pInv = createInvestment();//  
  3.   ... 
  4.   delete pInv;// pInv  

これは妥当に見えるが、いくつかの場合、fはcreateInvestmentからの投資対象を削除できない可能性がある.deleteの前にreturnが実行されている場合、オブジェクトはdeleteされません.
createInvestmentの戻りリソースが常に解放されるようにするには、制御フローがfから離れると、オブジェクトの構造関数が自動的にそれらのリソースを解放するオブジェクト内にリソースを配置する必要があります.オブジェクトにリソースを入れると、C++の「構造関数自動呼び出しメカニズム」に依存してリソースが解放されることを保証します.
多くのリソースはheap内に動的に割り当てられ、単一のブロックまたは関数内に使用される.これらは、制御フローがそのブロックまたは関数から離れるときに解放されるべきである.標準ライブラリで提供されるauto_ptrはこのような形式に対して設計されている.auto_ptrは「クラスポインタオブジェクト」、すなわちいわゆるスマートポインタであり、その解析関数は、その指すオブジェクトに対してdeleteを自動的に呼び出す.次はauto_の使用方法を示します.ptrは、f関数の潜在的なリソース漏洩の可能性を回避するために:

  
  
  
  
  1. void f() 
  2.   std::auto_ptr<Investment> pInv(createInvestment()); 
  3.              //  
  4.     ...      // pInv 
  5. }            // auto_ptr pInv 

この簡単な例では、「オブジェクトでリソースを管理する」という2つの重要な考え方を示します.
1.リソースを取得した直後に管理対象に入れます.
以上のコードでcreateInvestmentが返すリソースは、その管理者auto_として扱われます.ptrの初期値.リソースを取得した後、同じ文で管理オブジェクトを初期化します.リソースが取得された後、管理オブジェクトに割り当てられる場合があります.各リソースは、取得と同時に直ちに管理オブジェクトに格納されます.
2.管理対象は構造解析関数を用いて資源が解放されることを確保する
制御フローがブロックからどのように離れるかにかかわらず、オブジェクトが破棄され、その構造関数が自動的に呼び出され、以上のリソースが解放されます.
 
auto_のためptrが破棄されると自動的にその対象物が削除されるので、複数のauto_ptrは同時に同じオブジェクトを指します.
この問題を予防するためにauto_ptrには、copyコンストラクション関数またはcopy assignmentオペレータによって値を割り当てるとnullになり、得られたポインタが取得するリソースの一意の所有権がコピーされます.

  
  
  
  
  1. std::auto_ptr<Investment> pInv1(createInvestment()); 
  2.                   //pInv1 createInvestment  
  3. std::auto_ptr<Investment> pInv2(pInv1);//pInv2 ,pInv1 null 
  4.  
  5. pInv1 = pInv2;// pInv1 ,pInv2 null 

この奇妙な付与動作には、「auto_ptrによって管理されるリソースは、auto_ptronsilがそれを指すものが絶対に1つ以上ない必要がある」という下位条件が付加されています.auto_ptrは、リソースの動的割り当てを管理する最良の方法ではありません.STLコンテナは、その要素が正常な複製動作を発揮することを要求するため、これらのコンテナはauto_ptr.
auto_ptrの代替案は「参照カウント型スマートポインタ(RCSP)」である.RCSPもスマートポインタであり、どれだけのオブジェクトがあるリソースを指しているかを追跡し続け、誰も指さしていないときに自動的に削除する.RCSPが提供する行為はゴミ回収のようなものであり、RCSPが環状参照を破ることができないのとは異なる(たとえば、実際には使用されていない2つのオブジェクトが互いに指し合っているため、まだ「使用されている」状態にあるようです).
TR 1のtr 1::shared_ptrはRCSPで、fと書くことができます.

  
  
  
  
  1. void f() 
  2.   ... 
  3.   std::tr1::shared_ptr<Investment> pInv(createInvestment()); 
  4.                           //  
  5.   .....// pInv 
  6. }// shared_ptr pInv 

このコードはauto_をほとんど使用しているように見えます.ptrは同じですがshared_ptrのレプリケーション動作は正常になりました.

  
  
  
  
  1. void f() 
  2.   ... 
  3.   std::tr1::shared_ptr<Investment> pInv1(createInvestment()); 
  4.                    //pInv1  
  5.   std::tr1::shared_ptr<Investment> pInv2(pInv1);; 
  6.                   //pInv1 pInv2  
  7.   pInv1 = pInv2;  //  
  8.   ... 
  9. }  //pInv1 pInv2 ,  

tr1::shared_ptrは、STLの他の文脈で使用することができる.
atuo_ptrとtr 1::shared_ptrは両方ともその解析関数内でdelete[]ではなくdelete[]動作を行い、動的に割り当てられた配列にauto_を使用することを意味する.ptrとtr 1::shared_ptrはいい考えではない.しかし、使用すればコンパイルは通過する.
 
1.リソースの漏洩を防止するために、構造関数でリソースを取得し、構造関数でリソースを解放するRAIIオブジェクトの使用を示します.
2.2つのよく使われるRAIクラスはそれぞれtr 1::shared_ptrとauto_ptr.前者は通常、copy動作が直感的であるため、auto_を選択すると、より良い選択である.ptr、コピー動作はNULLを指します.