2009-08-21 81 views
4

一些智能指針模板,如boost :: 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。我更喜歡「空洞」。如果你能解引用一個無效指針,你會得到什麼。無論如何,這可能並不重要,因爲只要他試圖調用operator *,他就會得到一個關於解除引用void *的錯誤。 – 2009-08-21 15:37:33

+0

是的,void絕對比void *更好,因爲如果你嘗試解引用'shared_ptr '(這應該被認爲是錯誤),它會導致錯誤。 – 2009-08-21 15:39:41

+0

同意,把它改回來。總是去你的第一本能...... – 2009-08-21 15:43:13