Why my UniqPtr objects are double in size compared to std::unique_ptr?

In real applications I should stick to the standard library facilities, for practice and understanding how those facilities work I should try to implement my own.

Here I've implemented a simulation of the smart pointer unique_ptr:

#include<iostream>
#include <memory>


template <typename T>
class DefDel
{
public:
    template <typename U>
    void operator()(U* p)const
    {
        std::cout << "freeing memory...\n";
        delete p;
    }
};

template <typename T>
class DefDel<T[]>
{
public:
    template <typename U>
    void operator()(U* p)const
    {
        std::cout << "freeing memory of an array of objects...\n";
        delete[] p;
    }
};

template <typename T, typename D = DefDel<T>>
class UniqPtr final
{
public:
    UniqPtr(T* = nullptr, D = DefDel<T>{});
    UniqPtr(UniqPtr const&) = delete;
    UniqPtr(UniqPtr&&) noexcept;
    UniqPtr& operator =(UniqPtr const&) = delete;
    UniqPtr& operator =(UniqPtr&&) noexcept;
    ~UniqPtr();
    T& operator*();
    T const& operator*() const;
    T* operator->();
    T const* operator->() const;
    operator bool() const;

private:
    T* ptr_{nullptr};
    D del_{};
};

template <typename T, typename D>
UniqPtr<T, D>::UniqPtr(T* p, D del) :
    ptr_(p),
    del_(del)
{}

template <typename T, typename D>
UniqPtr<T, D>::UniqPtr(UniqPtr&& rhs) noexcept :
    ptr_(std::move(rhs.ptr_)),
    del_(std::move(rhs.del_))
{
    rhs.ptr_ = nullptr;
}

template <typename T, typename D>
UniqPtr<T, D>& UniqPtr<T, D>::operator = (UniqPtr&& rhs) noexcept
{
    if(this != &rhs)
    {
        ptr_ = std::move(rhs.ptr_);
        del_ = std::move(rhs.del_);
        rhs.ptr_ = nullptr;
    }
    return *this;
}

template <typename T, typename D>
UniqPtr<T, D>::~UniqPtr()
{
    del_(ptr_);
}

template <typename T, typename D>
T& UniqPtr<T, D>::operator*()
{
    return *ptr_;
}

template <typename T, typename D>
T const& UniqPtr<T, D>::operator*() const
{
    return *ptr_;
}

template <typename T, typename D>
T* UniqPtr<T, D>::operator->()
{
    return ptr_;
}

template <typename T, typename D>
T const* UniqPtr<T, D>::operator->() const
{
    return ptr_;
}

template <typename T, typename D>
UniqPtr<T, D>::operator bool() const
{
    return ptr_;
}

// for array
template <typename T, typename D>
class UniqPtr<T[], D> final
{
public:
    UniqPtr(T* = nullptr, D = DefDel<T[]>{});
    UniqPtr(UniqPtr const&) = delete;
    UniqPtr(UniqPtr&&) noexcept;
    UniqPtr& operator =(UniqPtr const&) = delete;
    UniqPtr& operator =(UniqPtr&&) noexcept;
    ~UniqPtr();
    T& operator*();
    T const& operator*() const;
    T* operator->();
    T const* operator->() const;
    operator bool() const;

private:
    T* ptr_{nullptr};
    D del_{};
};

template <typename T, typename D>
UniqPtr<T[], D>::UniqPtr(T* p, D del) :
    ptr_(p),
    del_(del)
{}

template <typename T, typename D>
UniqPtr<T[], D>::UniqPtr(UniqPtr&& rhs) noexcept :
    ptr_(std::move(rhs.ptr_)),
    del_(std::move(rhs.del_))
{
    rhs.ptr_ = nullptr;
}

template <typename T, typename D>
UniqPtr<T[], D>& UniqPtr<T[], D>::operator = (UniqPtr&& rhs) noexcept
{
    if(this != &rhs)
    {
        ptr_ = std::move(rhs.ptr_);
        del_ = std::move(rhs.del_);
        rhs.ptr_ = nullptr;
    }
    return *this;
}

template <typename T, typename D>
UniqPtr<T[], D>::~UniqPtr()
{
    del_(ptr_);
}

template <typename T, typename D>
T& UniqPtr<T[], D>::operator*()
{
    return *ptr_;
}

template <typename T, typename D>
T const& UniqPtr<T[], D>::operator*() const
{
    return *ptr_;
}

template <typename T, typename D>
T* UniqPtr<T[], D>::operator->()
{
    return ptr_;
}

template <typename T, typename D>
T const* UniqPtr<T[], D>::operator->() const
{
    return ptr_;
}

template <typename T, typename D>
UniqPtr<T[], D>::operator bool() const
{
    return ptr_;
}


int main()
{

    UniqPtr<int[]> upi(new int[3]{57});
    std::cout << sizeof(upi) << '\n';
    std::unique_ptr<int[], DefDel<int[]>> upi2(new int[3]{57});
    std::cout << sizeof(upi2) << '\n';
}
  • Why the size of my UniqPtr objects are double in size as std::unique_ptr (even being initialized with the same values)?

  • Is that because of my class is storing a Del_ object as a member?

  • If that is the problem then how could I achieve the very similar behavior as unique_ptr with 0 cost?



Read more here: https://stackoverflow.com/questions/64892525/why-my-uniqptr-objects-are-double-in-size-compared-to-stdunique-ptr

Content Attribution

This content was originally published by Maestro at Recent Questions - Stack Overflow, and is syndicated here via their RSS feed. You can read the original post over there.

%d bloggers like this: