3

DuplicateHandleで動作しないHANDLEのラッパーを作成しているので、代わりに、shared_ptrでハンドルをラップしようとしています。

次のコードを想像してみてください。

class CWrapper
{
public:
    CWrapper() :
        m_pHandle(new HANDLE, &CWrapper::Close)
    {
        //code to open handle
    }

private:
    void Close() 
    { 
        //code to close handle
    }

    std::shared_ptr<HANDLE> m_pHandle;
}

また、HANDLEパラメーターを使用してcloseを作成してみました(理想的ではありません)。いずれにせよ、「Termは0個の引数を取る関数に評価されません」というコンパイラエラーが発生します。これは暗黙のthisポインタによるものですか?これを修正するにはどうすればよいですか?共有ポインタからメンバー関数を呼び出すにはどうすればよいですか?

4

5 に答える 5

6

メンバー関数を呼び出すことはできませんが、次のようにグローバル関数であるカスタム デリーターを使用できます。

void my_deleter(Foo *ptr)
{
 delete ptr;
 std::cout<< "using custom deleter" <<std::endl;
}
shared_ptr<Foo> pf (new Foo, my_deleter); 
于 2010-06-20T12:20:44.907 に答える
5

内部から非静的メンバーにアクセスする必要がある場合は、その引数を適切Closeにバインドする必要がありますthis

CWrapper() :
   m_pHandle(new HANDLE, boost::bind(&CWrapper::Close, this, _1)) {
    //code to open handle
}

ただし、これには隠れたバグが含まれています。あなたのオブジェクトはコピー可能で、デリータを のオブジェクトにバインドします*this。ハンドルは作成した最初のラッパーに関連付けられますが、ラッパーをコピーすると、ハンドルは共有されますが、最初のラッパーに関連付けられます。このラッパーはもう存在しない可能性があります。

CWrapper getWrapper() { CWrapper w; return w;  }
CWrapper x = getWrapper();

そのコードが実行されて破棄されると、 の内部ハンドル ポインターの破棄により、 のコンストラクター呼び出しでバインドされたオブジェクトを使用しようとするxため、動作は未定義ですが、そのオブジェクトはもう存在しません!xw

これに対する解決策は、次のコードのように、ハンドルに関連付けられたデータをトップレベルのハンドル オブジェクトに格納しようとするのではなく、割り当てられたオブジェクト自体に格納することです。

class CWrapper
{
public:
  CWrapper():m_pHandle(new CHandle)
  { }

private:
    // This class cannot be copied
    class CHandle : boost::noncopyable {
      friend class CWrapper;

      CHandle() 
        :m_pHandle(new HANDLE) {
          // code to open handle
      }

      ~CHandle() {
        // code to close this handle, making use of 
        // auxilary data for whatever reason
      }

    private:
      boost::scoped_ptr<HANDLE> m_pHandle;
      // auxilary data associated with the handle...
    };

    boost::shared_ptr<CHandle> m_pHandle;
};

補助データはハンドルに保存されなくなりましたが、ラッパーのすべてのコピー間で共有されるデータと共に保存されます。共有データ自体は、通常のコンストラクタとデストラクタを使用して作成および破棄されます。

CWrapper getHandle() { return myHandle; }
CWrapper w = getHandle();

最後のラッパーが寿命を迎えると、すべてのラッパー間で明示的に共有されているハンドルが破棄されます。

于 2010-06-20T13:56:56.160 に答える
5

抽象化が間違っていると思います。

shared_ptrそれ自体はコピーできない共有リソースへのコピー可能な「ハンドル」を提供します。shared_ptr削除時に独自のクリーンアップを実行しないタイプで使用することは、最適な使用方法ではありません。

デストラクタでこの本質的にコピー不可能なリソースを適切にクリーンアップするクラスの単一の責任を作成する場合は、単一の責任が本来shared_ptrあるべき共有所有権を提供するために使用できます。(HANDLE単純なコピーを作成しようとする場合、コピーはHANDLE独立しているとは見なされません。コピーの所有者が存在する他のコピーについて知る必要があるように、最後のコピーは正しく閉じられている必要があります。)

class CWrapper
{
public:
    CWrapper()
    {
        // code to open handle
    }

    ~CWrapper()
    {
        // code to close handle
    }

private:
    // prevent copying
    CWrapper(const CWrapper&);
    CWrapper& operator=(const CWrapper&);

    HANDLE mHandle;
};

ハンドルを共有する必要がある場所を使用shared_ptr<CWrapper>します。これが冗長すぎると思われる場合は、typedef を使用できます。

カスタム デリーターは非常に複雑なソリューションです。

于 2010-06-20T12:50:58.683 に答える
3

私はそれをテストしていませんが、shooshによって提示されたアイデアに基づいて、次のようなメンバー関数を渡すことができる場合があります。

void Class::myDeleteMember(Foo *ptr)
{
 delete ptr;
 std::cout<< "using custom deleter" <<std::endl;
}
shared_ptr<Foo> pf (new Foo, boost::bind(&Class::myDeleteMember, _1)); 
于 2010-06-20T12:27:16.010 に答える
0

deleterboost::shared_ptr ドキュメントで を探します。直リンクは見つけられませんでしたが、基本的にはrefが0のときに呼ばれるファンクタです。

于 2010-06-20T12:21:19.710 に答える