2013-12-19 7 views
6

私は、ダブルポインタを取り込んでメモリを割り当てる従来の時代のコードを使用しています。実際LegacyAllocator機能がLegacyObjポインタのリンクリストを作成したファイルからの読み込み〜100行とミックスされ、そして私がことができると思いますものではありません別の関数で割り当てられたメモリで共有ポインタを使用する

struct LegacyObj 
{ 
    int a; 
    double b; 
}; 

void LegacyAllocator(LegacyObj** ppObj) 
{ 
    *ppObj = (LegacyObj*)malloc(sizeof(LegacyObj)); 
} 

void LegacyDeleter(LegacyObj** ppObj) 
{ 
    free(*ppObj); 
} 

:それの短縮例は、このようになります今すぐ書き直してしかし、私は、この関数の使用を少し安全にして、例外& tcから発生するメモリーリークを回避したいと考えています。私が思い描いた最初の解決策は、クラスでラップし、ctor/dtorでレガシー関数を呼び出すことでした。

class RAIIWrapper 
{ 
public: 
    RAIIWrapper() 
     :obj{nullptr} 
    { 
     ::LegacyAllocator(&obj); 
    } 
    RAIIWrapper(RAIIWrapper&& that) 
     : obj{ that.obj} 
    { 
     that.obj = nullptr; 
    } 
    RAIIWrapper& operator=(RAIIWrapper&& that) 
    { 
     RAIIWrapper copy{std::move(that)}; 
     std::swap(obj, copy.obj); 
     return *this; 
    } 
    ~RAIIWrapper() 
    { 
     ::LegacyDeleter(&obj); 
    } 

private: 
    LegacyObj* obj; 
}; 

しかし、私は好奇心が強い - std::shared_ptrstd::unique_ptrを使用してこれを行う方法はありますか?私は、元のポインタをLegacyAllocatorに渡し続けることなく、解決策を考え出すことができませんでした。

+0

unique_ptr'と 'shared_ptr'はアロケータを取ることはありません'、彼らだけ取ります削除者。ポインタを 'LegacyAllocator(&obj)'で自分自身に割り当て、 'operator()' – David

答えて

3

はい、あなたは例えば、std::unique_ptrまたはstd::shared_ptrとカスタム削除手段を使用することができますように正しく@Daveによって指摘、

struct Deleter { 
    void operator()(LegacyObj *p) const { 
    LegacyDeleter(&p); 
    } 
}; 

std::unique_ptr<LegacyObj, Deleter> MakeLegacyObj() { 
    LegacyObj *p = 0; 
    LegacyAllocator(&p); 
    return std::unique_ptr<LegacyObj, Deleter>(p); 
} 

std::unique_ptr<LegacyObj, Deleter> p = MakeLegacyObj(); 

をそして、これはあまりにもshared_ptrで動作します:

std::shared_ptr<LegacyObj> p = MakeLegacyObj(); 
+1

と 'std :: shared_ptr​​で' LegacyDeleter(&p) 'を呼び出す' unique_ptr'/'shared_ptr'のためのディテクタファンクタを作成します。 p = MakeLegacyObj(); 'too too – David

+0

@Dave:うん、良い点。 – vitaut

+0

おかげさまで、カスタムのDeleter Functorを作成するような感じがしました。 –

0

メモリを削除するにはunique_ptrを使用できますが、メモリはnewではなくmallocを使用して割り当てられるため、カスタムDeleterクラスを指定する必要があります。

さらに、newを使用するように割り当てコードを変更し、unique_ptrを使用してください。この道を進むと、アロケータはメモリへのポインタの代わりにunique_ptrを返すようにすることができます。ここでは、独自のカスタム削除手段を提供する必要があると仮定すると、

は、あなたがそれを行う可能性があります一つの方法である:

template <typename T> 
class MallocDeleter 
{ 
public: 
    void operator() (T* obj) const 
    { 
    LegacyDeleter (*obj); 
    } 
}; 

typedef std::unique_ptr <LegacyObj, MallocDeleter <LegacyObj>> unique_legacy_ptr; 

あなたはまた、おそらく代わりに初期化するので、LegacyAllocatorを呼び出すことによって割り当てmake_unique_legacyタイプの機能を提供することができあなた自身unique_ptr

0

次のようにunique_ptrのファクトリ関数を作成できます。

typedef void(* LegacyDeleterType)(LegacyObj*); 
typedef std::unique_ptr<LegacyObj,LegacyDeleterType> UniqueLegacyPtr; 

UniqueLegacyPtr makeUniqueLegacyObj() 
{ 
    LegacyObj * p = nullptr; 
    LegacyAllocator(&p); 
    return UniqueLegacyPtr(p, [](LegacyObj*p){ LegacyDeleter(&p); }); 
} 

あなたは今unique_ptr Sを作成するためにそれを使用することができますし、また、建設時に自動的にshared_ptrのキャプチャカスタム削除手段に割り当てることができます。

int main() 
{ 
    auto unique = makeUniqueLegacyObj(); 
    std::shared_ptr<LegacyObj> shared = makeUniqueLegacyObj(); 
} 
関連する問題