Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Smart Pointer Custom Deleter

For education purposes only, I am writing a small smart pointer class, for the moment not a shared one just a simple one like the unique_ptr in C++ 11. What I want is not a fully working implementation, but just the base, creation, default/custom delete and so on.

I've been trying to look at the implementation of the standard inside Microsoft visual studio, and I did catch the general implementation but I am stuck with the default/custom delete. So my question is, what is the best technique to implement such a feature?

It is possible to implement it easily just for educational purposes or at the end it's something too complicated and so not worth?

cheers

Hi Ami,

what do you think about something like that?

template <class _Ty>
    struct default_delete
    {

        constexpr default_delete() = default;

        void operator()(_Ty* Ptr)
        {

        std::cout << "Default Delete" << std::endl;

        }

    };


template <class T, class _Dl=default_delete<T>>
            class Smart_Pointer2_Base;

    template <class T, class _Dl>
    class Smart_Pointer2_Base
    {
        T *ptr;  // Actual pointer
        _Dl _deleter;
    public:
        // Constructor
        explicit Smart_Pointer2_Base(T *p = NULL) { ptr = p; }

        Smart_Pointer2_Base(T* p, _Dl) { prt = p; _deleter = _Dl; }

        // Destructor
        ~Smart_Pointer2_Base() { _deleter(ptr);}

        // Overloading dereferencing operator
        T & operator * () { return *ptr; }


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


int main()
{

    struct CloserStruct {
        void operator()(int* toDelete) { std::cout << "Custom Delete"<<std::endl; }
    };
    smtpr::Smart_Pointer2_Base<int, CloserStruct> pi(new int(5));

return 0;
}
like image 272
user1583007 Avatar asked Sep 26 '22 08:09

user1583007


1 Answers

This uses something called type erasure. While there are C++ libraries that do it (e.g., boost::any), it's not too difficult in this case.

Say you have some custom deleter:

struct deleter
{
    void operator()(void *)
    {
        cout << "deleting" << endl;
        // Do some other stuff.
    }
};

but you want to support others with the same signature without forcing your users to use virtual functions in their own code.

Start by defining a base class:

struct base_deleter_holder
{
    virtual void delete_it(void *p) = 0;
};

Your class will hold a pointer to this base class.

Now write a derived class that is dependent on the actual deleter type:

template<class Deleter>
struct deleter_holder :
    public base_deleter_holder
{
    Deleter m_d;

    explicit deleter_holder(const Deleter &d) : m_d(d)
    {}
    virtual void delete_it(void *p)
    {
        m_d(p);
    }
};

You can add a utility function to help you create objects of its type:

template<class Deleter>
base_deleter_holder *make_deleter_holder(const Deleter &d)
{
    return new deleter_holder<Deleter>(d);
}

Now, when someone calls your template function with a deleter, you can create the actual derived type, and store it in your class in a base pointer. Using virtual functions, you can use the base pointer to call the derived class's methods:

    deleter d;

    // pd should be a member of your pointer class.
    base_deleter_holder *pd = make_deleter_holder(d);

    // Here's how to use it.
    pd->delete_it(nullptr);

Full example:

#include <functional> 
#include <iostream> 


using namespace std; 


struct base_deleter_holder 
{ 
    virtual void delete_it(void *p) = 0; 
}; 


template<class Deleter> 
struct deleter_holder :  
    public base_deleter_holder 
{ 
    Deleter m_d; 

    explicit deleter_holder(const Deleter &d) : m_d(d) 
    {} 
    virtual void delete_it(void *p) 
    { 
        m_d(p); 
    } 
}; 


struct deleter 
{ 
    void operator()(void *) 
    { 
        cout << "deleting" << endl; 
    } 
}; 


template<class Deleter> 
base_deleter_holder *make_deleter_holder(const Deleter &d) 
{ 
    return new deleter_holder<Deleter>(d); 
} 


int main() 
{ 
    deleter d; 
    base_deleter_holder *pd = make_deleter_holder(d); 
    pd->delete_it(nullptr); 
} 
like image 196
Ami Tavory Avatar answered Sep 29 '22 05:09

Ami Tavory