2009-08-21 4 views
4

なブーストのようないくつかのスマートポインタテンプレート、:: shared_ptrのは、任意のオブジェクトを保持するために、ボイドでインスタンス化することができる。voidでインスタンス化できるスマートポインタの実装方法は?

以下

http://www.boost.org/doc/libs/1_39_0/libs/smart_ptr/sp_techniques.html#pvoid

は、最小限のscoped_ptrを実装です。 voidでインスタンス化されると、コンパイラは、逆参照演算子で不正な "voidへの参照"が形成されることについて不平を言う。 「代替失敗は誤りではない」(SFINAE)ルールはこのような状況をカバーしていないようです。

どのようにしてscoped_ptrを実装できますか?特に、テンプレートの専門化を書く代わりに、それがありますか?これにより、現実的なスマートポインタの実装による大きなコードの重複が発生します。

#include <cstdlib> 

template<typename T> 
void destroy(T* ptr) 
{ 
    delete ptr; 
} 

class scoped_ptr_impl_base 
{ 
public: 
    virtual ~scoped_ptr_impl_base() { } 
}; 

template<typename T, typename F> 
class scoped_ptr_impl : public scoped_ptr_impl_base 
{ 
public: 
    scoped_ptr_impl(T* ptr, F dtor) 
     : m_ptr(ptr), m_dtor(dtor) 
    { 
    } 

    virtual ~scoped_ptr_impl() 
    { 
     m_dtor(m_ptr); 
    } 

private: 
    T* m_ptr; 
    F m_dtor; 
}; 

template<typename T> 
class scoped_ptr 
{ 
public: 
    explicit scoped_ptr(T* ptr = 0) 
     : m_ptr(ptr), 
      m_impl(new scoped_ptr_impl<T, void (*)(T*)>(&destroy<T>)) 
    { 
    } 

    template<typename F> 
    scoped_ptr(T* ptr, F dtor) 
     : m_ptr(ptr), 
      m_impl(new scoped_ptr_impl<T, F>(ptr, dtor)) 
    { 
    } 

    ~scoped_ptr() 
    { 
     delete m_impl; 
    } 

    T& operator*() 
    { 
     return *m_ptr; 
    } 

    T* operator->() 
    { 
     return m_ptr; 
    } 

private: 
    T* m_ptr; 
    scoped_ptr_impl_base* m_impl; 

    scoped_ptr(const scoped_ptr&); 
    scoped_ptr& operator=(const scoped_ptr&); 
}; 

int main() 
{ 
    scoped_ptr<void> p(std::malloc(1), std::free); 
    // scoped_ptr.cpp: In instantiation of `scoped_ptr<void>': 
    // scoped_ptr.cpp:76: instantiated from here 
    // scoped_ptr.cpp:56: error: forming reference to void 
    // (g++ 4.3.3) 

    return 0; 
} 

答えて

8

あなたは参照型用の型特性を使用することができます。

template<typename T> 
struct type_trait 
{ 
    typedef T& reference; 
}; 

template<> 
struct type_trait<void> 
{ 
    typedef void reference; 
}; 

、あなたのscoped_ptr_implに:

typename type_trait<T>::reference operator*() 
{ 
    return *m_ptr; 
} 

ないvoidがが専門で右のタイプであれば確認してください。どのようなタイプを返すのですか?

+0

+1。私は「無効」が好きだった。これは、voidポインタを逆参照できる場合に得られるものです。とにかく、それは重要ではないでしょう。演算子*を呼び出そうとすると、void *の逆参照についてのエラーが発生するためです。 –

+0

確かに、 'shared_ptr '(エラーと見なすべき)を逆参照しようとすると、エラーが発生するので、voidはvoid *よりも優れています。 –

+0

合意し、元に戻しました。いつもあなたの最初の本能と一緒に行く... –

関連する問題