如何实现可以用void实例化的智能指针?

问题描述:

一些智能指针模板,如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; 
} 

你可以使用一个类型特征的引用类型:

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