搜索

首页  >  问答  >  正文

c++ - 如何在自己实现shared_ptr时,使得定义的shareda_ptr类模板可以接受一个可调用对象?

template <typename T>
class shared_ptr {
public:
    shared_ptr(): p(nullptr), use(new std::size_t(1)) { }
    explicit shared_ptr(T *pt): p(pt), use(new std::size_t(1)) {    }
    shared_ptr(const shared_ptr &sp): p(sp.p), use(sp.use) { if (use) ++*use; }
    shared_ptr& operator=(const shared_ptr&);
    ~shared_ptr();
    T& operator*() { return *p; }
    const T& operator*() const { return *p; }
private:
    T *p;
    std::size_t *use;
};

template <typename T>
shared_ptr<T>::~shared_ptr() {
    if (use && 0 == --*use) {
        delete p;   // del ? del(p) : delete p;
        delete use;
    }
}

如上所示。是C++ Primer 第五版16.1.6节的一个问题,请问我应该给shared_ptr类增加一个什么类型的成员del,才能够使得这个类可以接受一个可调用对象,此对象的目的是清理动态内存分配的指针,但是可以自定义这个对象的行为。
谢谢!

PHP中文网PHP中文网2803 天前454

全部回复(3)我来回复

  • 迷茫

    迷茫2017-04-17 13:21:44

    可以参考一下。。。

    template <typename Tp>
    class AutoCleanHelperBase
    {
    public:
        AutoCleanHelperBase(Tp* ptr)
            :m_ptr(ptr)
        { }
    
        virtual void destroy()
        {}
    
    protected:
        Tp* m_ptr;
    };
    
    template <typename Tp, typename Deleter>
    class AutoCleanHelper;
    
    template <typename Tp>
    class AutoCleanHelper<Tp, void> : public AutoCleanHelperBase<Tp>
    {
    public:
        AutoCleanHelper(Tp* ptr)
            :AutoCleanHelperBase<Tp>(ptr)
        { }
    
        void destroy()
        {
            delete this->m_ptr;
        }
    };
    
    template <typename Tp, typename Deleter>
    class AutoCleanHelper: public AutoCleanHelperBase<Tp>
    {
    public:
        AutoCleanHelper(Tp* ptr, Deleter del)
            :AutoCleanHelperBase<Tp>(ptr)
            ,m_del(del)
        { }
    
        void destroy()
        {
            (this->m_ptr->*m_del)();
        }
    
    private:
        Deleter m_del;
    };
    
    template <typename Tp>
    class AutoClean
    {
    public:
        template <typename Tp1>
        AutoClean(Tp1* ptr)
            :m_helper(new AutoCleanHelper<Tp1, void>(ptr))
        {}
    
        template <typename Tp1, typename Deleter>
        AutoClean(Tp1* ptr, Deleter deleter)
            :m_helper(new AutoCleanHelper<Tp1, Deleter>(ptr, deleter))
        {}
    
        ~AutoClean()
        {
            m_helper->destroy();
            delete m_helper;
        }
    
    private:
        AutoCleanHelperBase<Tp>* m_helper;
    };
    
    class CanDestroy
    {
    public:
        ~ CanDestroy()
        {
            std::cout <<"I'm destroy now !!!\n";
        }
    };
    
    class ExplicitDestroy
    {
    public:
        void destroy()
        {
            std::cout <<"I'm also destroy now !!!\n";
        }
    };
    
    int main()
    {
        AutoClean<CanDestroy> clean1(new CanDestroy);
    
        AutoClean<ExplicitDestroy> clean2(new ExplicitDestroy, &ExplicitDestroy::destroy);
    
        return 0;
    }

    回复
    0
  • PHP中文网

    PHP中文网2017-04-17 13:21:44

    可在shared_ptr里维护一个类型为void (*)(T*)的函数指针,然后在需要释放内存的时候调一下这个函数。一个简单的例子:

    void release(somePointer* ptr) {
        delete ptr;
        ptr = nullptr;    
    }
    

    我太天真了=,-,你可以看看这个回答 关于c++中,shared_ptr中的删除器

    回复
    0
  • 大家讲道理

    大家讲道理2017-04-17 13:21:44

    参考了araraloren的回答,感谢!

    template <typename T>
    class Contents {
    public:
        Contents(T* pt): contents(pt) { }
        virtual void destory() {    }
    protected:
        T* contents;
    };
    
    template <typename T, typename D>
    class ContentsWithDeleter;
    
    template <typename T>
    class ContentsWithDeleter<T, void> : public Contents<T> {
    public:
        ContentsWithDeleter(T *pt): Contents<T>(pt) {  }
        void destory() override { delete this->contents; }
    };
    
    template <typename T, typename D>
    class ContentsWithDeleter : public Contents<T> {
    public:
        ContentsWithDeleter(T *pt, D del): Contents<T>(pt), deleter(del) {  }
        void destory() override { deleter(this->contents); }
    private:
        D deleter;
    };
    
    template <typename T>
    class shared_ptr {  // todo
    public:
        template <typename Tp>
        shared_ptr(Tp *ptr): p(new ContentsWithDeleter<Tp, void>(ptr)), use(new std::size_t(1)) { }
        template <typename Tp, typename D>
        shared_ptr(Tp *ptr, D del): p(new ContentsWithDeleter<Tp, D>(ptr, del)), use(new std::size_t(1)) {    }
        shared_ptr(const shared_ptr &sp): p(sp.p), use(sp.use) { if (use) ++*use; }
        shared_ptr& operator=(const shared_ptr&);
        ~shared_ptr();
        T& operator*() { return *p; }
        const T& operator*() const { return *p; }
    private:
        Contents<T> *p;
        std::size_t *use;
    };
    
    template <typename T>
    shared_ptr<T>::~shared_ptr() {
        if (use && 0 == --*use) {
            p->destory();   // del ? del(p) : delete p;
            delete p;
            delete use;
        }
    }
    
    template <typename T>
    shared_ptr<T>& shared_ptr<T>::operator=(const shared_ptr<T> &rhs) {
        if (rhs.use) ++*rhs.use;
        if (use && 0 == --*use) {
            p->destory();
            delete p;
            delete use;
        }
        p = rhs.p;
        use = rhs.use;
        return *this;
    }

    回复
    0
  • 取消回复