2017-08-26 7 views
4

を使用して関数を作成し、破壊し、それが提供しています。createObject(...)destroy(...)を。私はそれをいくつかのより現代的な建設/破壊の仕組みに包み込み、スマートな指針でそれらを使用したいと思います。私はある時点でオブジェクトを破壊することを忘れてしまったり、何か例外が発生したりするのではないかと恐れています。ラッピングCは、私は、オブジェクトの作成と破棄を扱ういくつかのC APIを持つスマートポインタ

私はshared_ptrのカスタムディレクター機能を認識していますが、createOjbect関数が初期化を処理するため、newを明示的に呼び出すことはできません。

この場合、STLスマートポインタを使用できますか?この状況では、コンストラクタでの初期化、デストラクタでの破壊、参照カウントを実装するクラスを最初から実装する必要がありますか?

+1

:私は、このオブジェクトは、多くの宮殿で共有したいので、私は共有ポインタを使用して、それを包んアキラの提案@に基づいて

、およびラムダあなたのクラスのrefカウンター?コンストラクタでcreateObjectを呼び出し、デストラクタで破棄し、クラスにスマートポインタを返す静的ファクトリ関数を提供するだけです。スマートポインタがrefcounter部分を処理します。あなたのクラスが最終的に破棄されると、自動的に破壊が呼び出されます –

+0

createObjectは何を返しますか?何がかかりますか?あなたの答えに応じて、改善があるかもしれません。 – Yakk

答えて

6

std::shared_ptrは、cutstomの作成者と削除者でオブジェクトを作成して削除することができますが、newではなく、作成者機能を使用する必要があります。

私たちは、次のクリエーターとデリータ持っている、のは、考えてみましょう:単純に次の操作を行い、上記の関数によって作成されたFooのインスタンスを管理するには

typedef struct { 
    int m_int; 
    double m_double; 
} Foo; 

Foo* createObject(int i_val, double d_val) { 
    Foo* output = (Foo*)malloc(sizeof(Foo)); 

    output->m_int = i_val; 
    output->m_double = d_val; 

    puts("Foo created."); 
    return output; 
} 

void destroy(Foo* obj) { 
    free(obj); 
    puts("Foo destroyed.");   
} 

を:

使用
std::shared_ptr<Foo> foo(createObject(32, 3.14), destroy); 

std::shared_ptrは、オブジェクトの所有権を共有したくない場合はオーバーヘッドです。この場合、std::unique_ptrは、はるかに優れていますが、このタイプのためにあなたはそれが管理Fooインスタンスを削除することが可能なカスタム削除手段ファンクタを定義する必要があります。

struct FooDeleter { 
    void operator()(Foo* p) const { 
     destroy(p); 
    } 
}; 
using FooWrapper = std::unique_ptr<Foo, FooDeleter>; 

/* ... */ 

FooWrapper foo(createObject(32, 3.14)); 
+1

私は、Deleter関数としてCを無料で渡すことができることをよく言います。 –

1

C++ 17を。

template<auto X> using constant_t=std::integral_constant<std::decay_t<decltype(X)>, X> 
template<auto X> constexpr constant_t<X> constant{}; 
template<class T, auto dtor> using smart_unique_ptr=std::unique_ptr< T, constant_t<dtor> >; 

は今、あなたはBob* createBob(some_args...)destroyBob(Bob*)Bobを包むCのAPIを持っているとします

using unique_bob=smart_unique_ptr< Bob, destroyBob >; 
unique_bob make_unique_bob(some_args args){ 
    return unique_bob(createBob(args)); 
} 

unique_bobが暗黙のうちにshared_ptr<Bob>に移動することができます。デストラクタ署名がvoid(T*)であると仮定

template<class T, void(*dtor)(T*)> using smart_unique_ptr=std::unique_ptr< T, std::integral_constant<decltype(dtor),dtor> >; 

余分な仮定のビットは、C++ 14でこの作業を行うことができます。 C++ 11では

あなたがゼロオーバーヘッドunqiue PTRSのための新しいステートレス関数ポインタディスパッチャを記述する必要があります。

+0

私はあなたの解決策が 'std :: integral_constant'で好きです。 – Akira

0

私の場合のための完全なソリューションを投稿:あなたが必要な理由

// coming from some API: 
struct SomeStruct; 
bool initializedata(SomeStruct **data); 
bool destorycdata(SomeStruct **data); 

class SomeStructWrapper 
{ 
public: 
    SomeStructWrapper() 
    { 
     SomeStruct* data; 
     if(initializedata(&data)) 
     { 
      m_data = std::shared_ptr<SomeStruct>(data, [](SomeStruct* ptr){ 
       destorycdata(&ptr); 
      }); 
     } 
     else 
     { 
      throw std::runtime_error("Data was not initalized"); 
     } 
    } 

    const SomeStruct* operator->() const {return m_data.get();} 
    SomeStruct* operator->() {return m_data.get();} 

private: 
    std::shared_ptr<SomeStruct> m_data; 
}; 
関連する問題