0

RAII の方法でリソースを管理するクラスがあるとします。

class C
{
   HANDLE hResource_;

   // prevent sharing the ownership over the resource among multiple instances of C
   C(const C&);
   C& operator=(const C&);

public:
   C() : hResource_(INVALID_HANDLE){}

   C(int arg1, const std::string& arg2,...)
   {
      ...
      allocResource(arg1, arg2, ...);
      ...
   }

   ~C
   {
      ...
      FreeResource(hResource_);
      hResource_ = INVALID_HANDLE;
      ...
   }

   void allocResource(int arg1, const std::string& arg2, ...)
   {
      if(hResource_ == INVALID_HANDLE)
      {
          hResource_ = AllocateResource(arg1, arg2,...);
      }
   }

   HANDLE handle() {return hResource_;}
};

そのコンストラクターは、リソースの割り当てに必要ないくつかのパラメーターを受け取り、そのインスタンスを作成して使用し、いくつかのスコープ内に置くことができます。

// some global function 
void goo()
{
   C c(123, "test");
   UseResource(c.handle(),...);
   ... 
}

のインスタンスをあるクラスのメンバーにしたいとしましょう。また、の c-torCで発生するリソースの割り当てを遅らせたいとします。Cこれには、Cのデフォルトの c-tor と、Cリソース割り当てを実行する のメンバー関数 (たとえばallocResource()、 を呼び出すAllocateResource()) が必要です。

class A
{
   C c_;

public:
   void foo1()
   {
      ...
      c_.allocResource(123, "test"); 
      UseResource(c_.handle(),...);
      ...
   }   

   void foo2()
   {
      ...         
      UseResource(c_.handle(),...);
      ...
   }   
};

専用関数を使用することで、私はC好きではない方法で の内部を公開しています。

私の質問は次のとおりです。このアプローチは、遅延初期化を有効にする一般的な方法ですか? 代替手段はありますか?


編集:これは、以下の (MSalters の) 提案に関する可能なクラス設計です。

class C
{
   HANDLE hResource_;

   // prevent sharing the ownership over the resource 
   // among multiple instances of C
   C(const C&);
   C& operator=(const C&);

public:      

   // prevent object creation if resource cannot be acquired
   C(int arg1, const std::string& arg2,...)
   {          
      hResource_ = AllocateResource(arg1, arg2,...);

      // assumption: AllocateResource() returns 
      // INVALID_HANDLE in case of failure
      if(hResource_ == INVALID_HANDLE)
         throw resource_acquisition_exception();
   }

   ~C
   {
      ...
      FreeResource(hResource_);
      hResource_ = INVALID_HANDLE;
      ...
   }

   HANDLE handle() {return hResource_;}
};

class A
{
   std::unique_ptr<C> c_;

public:
   void foo1()
   {
      try
      {
         ...
         c_ = std::unique_ptr<C>(new C(123, "test"));
         UseResource(c_->handle(),...);
         ...
      }
      catch(const resource_acquisition_exception& exc)
      {
         ...
      }
      catch(...)
      {
         ...
      }
   }   

   void foo2()
   {
      ...         
      UseResource(c_->handle(),...);
      ...
   }   
};
4

2 に答える 2

4

いいえ、これは RAII を行う一般的な方法ではありません。実際、これはまったく RAII ではありません。に必要なリソースを割り当てることができない場合はC、 を作成しないでくださいC

于 2012-04-17T11:24:16.633 に答える
1

問題は確かにCの内部を公開していることですが、handle()関数を使用して既に公開しているため、遅延インスタンス化を実行する可能性はすでに制限されています。

ハンドラーを取得するだけでなく、実際にCを呼び出して何かを実行した方が簡単です。ただし、handle()はゲッターであり、必要なパラメーターをコンストラクターで既に渡すことができるため(インスタンス化せずに、パラメーターを格納することで)、handle()でhResource_が有効かどうかを確認し、有効でない場合はリソースを割り当てることができます(割り当てが失敗した場合は例外をスローします)。

于 2012-04-17T11:28:13.513 に答える