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

发布于 2024-08-02 17:44:08 字数 1915 浏览 7 评论 0原文

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

Some smart pointer templates, such as boost::shared_ptr, may be instantiated with void to hold an arbitrary object:

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

Below is a minimal scoped_ptr implementation. When instantiated with void, the compiler complains about an illegal "reference to void" being formed in the dereference operator. It seems the "substitution failure is not an error" (SFINAE) rule does not cover this situation.

How then is it possible to implement a scoped_ptr? In particular, is there an alternative to writing a template specialization? This would cause large code reduplication with a realistic smart pointer implementation.

#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;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

痞味浪人 2024-08-09 17:44:08

您可以对引用类型使用类型特征:

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 是否是专业化中的正确类型。你希望它返回什么类型?

You could use a type trait for the reference type:

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

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

then in your scoped_ptr_impl :

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

Not sure if void is the right type in the specialisation though . What type do you want it to return?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文