c++ smart shared pointer for both pointers and non pointer types

I created this shared pointer mainly to use it as RAII for handles that have to be shared between classes or threads

for pointers : it supports raw pointers and pointer to classes and arrays and also support classes inheriting from ref_base class to save an allocation for the reference counter

for non pointers types : they must be nullable and aren’t arrays or inheriting from ref_base

this is my code :

#include <atomic> #include <type_traits> #include <Windows.h>  using namespace std;  #define HAS_TYPE(NAME) \ template<typename, typename = void> \ struct has_type_##NAME: std::false_type \ {}; \ template<typename T> \ struct has_type_##NAME<T, void_t<typename T::NAME>>: std::true_type \ {} \  HAS_TYPE(pointer);   template <class T, bool is_it_array = false> struct default_sp_deleter {     void operator()(T *ptr)     {         delete ptr;     } };  template <class T> struct default_sp_deleter<T, true> {     void operator()(T *ptr)     {         delete[] ptr;     } };  template <class T, class D, bool inherit, bool has_pointer> struct sp_data {};  template <class T, class D> struct sp_data<T, D, true, true> {     using pointer = typename D::pointer;     pointer ptr;     D deleter;     sp_data() : ptr(pointer())     {}     sp_data(pointer p) : ptr(p)     {}     sp_data(pointer p, D del) : ptr(p), deleter(del)     {} };  template <class T, class D> struct sp_data<T, D, true, false> {     using pointer = T*;     pointer ptr;     D deleter;     sp_data() : ptr(pointer())     {}     sp_data(pointer p) : ptr(p)     {}     sp_data(pointer p, D del) : ptr(p), deleter(del)     {} };  template <class T, class D> struct sp_data<T, D, false, false> {     using pointer = T*;     pointer ptr;     D deleter;     atomic<uintptr_t> *ref_count;     sp_data() : ptr(pointer()), ref_count(new atomic<uintptr_t>(0))     {}      sp_data(pointer p) : ptr(p), ref_count(new atomic<uintptr_t>(0))     {}      sp_data(pointer p, D del) : ptr(p), deleter(del), ref_count(new atomic<uintptr_t>(0))     {}      sp_data(const sp_data<T, D, false, false>& data) : ptr(data.ptr), ref_count(data.ref_count)     {}      ~sp_data()     {}      sp_data& operator=(const sp_data<T, D, false, false>& data)     {         ptr = data.ptr;         ref_count = data.ref_count;         return *this;     }  };  template <class T, class D> struct sp_data<T, D, false, true> {     using pointer = typename D::pointer;     pointer ptr;     D deleter;     atomic<uintptr_t> *ref_count;     sp_data() : ptr(pointer()), ref_count(new atomic<uintptr_t>(0))     {}      sp_data(pointer p) : ptr(p), ref_count(new atomic<uintptr_t>(0))     {}      sp_data(pointer p, D del) : ptr(p), deleter(del), ref_count(new atomic<uintptr_t>(0))     {}      sp_data(const sp_data<T, D, false, false>& data) : ptr(data.ptr), ref_count(data.ref_count)     {}      template     <class U>     sp_data(const sp_data<U, D, false, false>& data) : ptr(data.ptr)     {      }      ~sp_data()     {}      sp_data& operator=(const sp_data<T, D, false, false>& data)     {         ref_count = data.ref_count;         ptr = data.ptr;         return *this;     } };  class ref_base;  template <class T, class Deleter =  default_sp_deleter<typename std::remove_all_extents<T>::type, std::is_array<T>::value>> class sp {      using elem_type = typename std::remove_all_extents<T>::type;      using pointer = typename sp_data<elem_type, Deleter, std::is_base_of<ref_base, T>::value, has_type_pointer<Deleter>::value>::pointer;      sp_data<elem_type, Deleter, std::is_base_of<ref_base, pointer>::value, has_type_pointer<Deleter>::value> data;  public :      using element_type = typename std::remove_pointer_t<pointer>;      template<typename, typename> friend class sp;      sp()     {}      sp(pointer p)     {         data.ptr = p;         if (get() != pointer())             inc_ref();     }      sp(const sp<T, Deleter>& rhs) : data(rhs.data)     {         if (get() != pointer())             inc_ref();     }      sp(sp<T, Deleter>&& rhs) : data(rhs.data)     {         rhs.data.ptr = pointer();     }      template     <class U>     sp(const sp<U, Deleter>& rhs) : data(rhs.data)     {         if (get() != pointer())             inc_ref();     }      template     <class U>     sp(sp<U, Deleter>&& rhs) : data(rhs.data)     {         rhs.data.ptr = pointer();     }      template     <class U, typename std::enable_if<std::is_convertible<U, pointer>::value && !std::is_same<U, pointer>::value, bool>::type = true>      sp(U value)     {         data.ptr = value;         if (get() != pointer())             inc_ref();     }      ~sp()     {         reset();     }      sp<T, Deleter>& operator=(const sp<T, Deleter>& rhs)     {         reset();         data = rhs.data;         if (get() != pointer())             inc_ref();         return *this;     }      sp<T, Deleter>& operator=(sp<T, Deleter>&& rhs)     {         reset();         data = rhs.data;         if (get() != pointer())             inc_ref();         rhs.reset();         return *this;     }      template     <class U>     sp<T, Deleter>& operator=(const sp<U, Deleter>& rhs)     {         reset();         data = rhs.data;         if (get() != pointer())             inc_ref();         return *this;     }      template     <class U>     sp<T, Deleter>& operator=(sp<U, Deleter>&& rhs)     {         reset();         data = rhs.data;         if (get() != pointer())             inc_ref();         rhs.reset();         return *this;     }      pointer get() const     {         return data.ptr;     }      template     <class U = pointer>      typename std::enable_if<is_pointer<U>::value, element_type&>::type     operator*()     {         return *data.ptr;     }      template     <class U = pointer>     typename std::enable_if<!std::is_pointer<U>::value, pointer&>::type operator&()     {         return &data.ptr;     }       pointer operator->()     {         return get();     }      long use_count()     {         if (get() == pointer())             return 0;         return private_use_count();     }      bool unique()     {         return use_count() == 1;     }      operator bool()     {         return get() != pointer();     }      Deleter& get_deleter()     {         return data.deleter;     }      void reset(pointer ptr = pointer())     {         if (get() == ptr)             return;          if (has_counter() && !dec_ref())         {             get_deleter()(get());         }          release_ref_counter();          data.ptr = ptr;         if (get() != pointer())         {             setup_counter();             inc_ref();         }     }  private :      template<class U = element_type>     typename enable_if<is_base_of<ref_base, U>::value && std::is_pointer<pointer>::value>::type inc_ref()     {         get()->inc_ref();     }      // currently this type of members is broken and shouldn't be used :     // if Deleter::pointer exists it mustn't inherit from ref_base      template<class U = element_type>     typename enable_if<is_base_of<ref_base, U>::value && !std::is_pointer<pointer>::value>::type inc_ref()     {         data.ptr.inc_ref();     }      template<class U = element_type>     typename enable_if<!is_base_of<ref_base, U>::value>::type inc_ref()     {         ++(*data.ref_count);     }      template<class U = element_type>     typename std::enable_if<std::is_base_of<ref_base, U>::value && std::is_pointer<pointer>::value, uintptr_t>::type dec_ref()     {         return get()->dec_ref();     }      template<class U = element_type>     typename std::enable_if<std::is_base_of<ref_base, U>::value && !std::is_pointer<pointer>::value, uintptr_t>::type dec_ref()     {         return data.ptr.dec_ref();     }      template<class U = element_type>     typename std::enable_if<!std::is_base_of<ref_base, U>::value, uintptr_t>::type dec_ref()     {         --(*data.ref_count);         return data.ref_count->load();     }      template<class U = element_type>     typename std::enable_if<std::is_base_of<ref_base, U>::value && std::is_pointer<pointer>::value, uintptr_t>::type private_use_count()     {         return get()->use_count();     }      template<class U = element_type>     typename std::enable_if<std::is_base_of<ref_base, U>::value && !std::is_pointer<pointer>::value, uintptr_t>::type private_use_count()     {         return data.ptr.use_count();     }      template<class U = element_type>     typename std::enable_if<!std::is_base_of<ref_base, U>::value, uintptr_t>::type private_use_count()     {         return data.ref_count->load();     }      template<class U = element_type>     typename std::enable_if<std::is_base_of<ref_base, U>::value>::type release_ref_counter()     {}      template<class U = element_type>     typename std::enable_if<!std::is_base_of<ref_base, U>::value>::type release_ref_counter()     {         if (data.ref_count && !(*data.ref_count))         {             delete data.ref_count;         }         data.ref_count = nullptr;     }      template<class U = element_type>     typename std::enable_if<std::is_base_of<ref_base, U>::value>::type setup_counter()     {}      template<class U = element_type>     typename std::enable_if<!std::is_base_of<ref_base, U>::value>::type setup_counter()     {         data.ref_count = new atomic<uintptr_t>(0);     }      template<class U = element_type>     typename std::enable_if<std::is_base_of<ref_base, U>::value, bool>::type has_counter()     {         return get() != pointer();     }      template<class U = element_type>     typename std::enable_if<!std::is_base_of<ref_base, U>::value, bool>::type has_counter()     {         return data.ref_count != nullptr;     }  };   class ref_base {  public :      template<typename, typename> friend class sp;      ref_base() : ref_count(0)     {}      ref_base(const ref_base&) : ref_count(0)     {}      ref_base(ref_base&&) : ref_count(0)     {}      ~ref_base()     {}      ref_base& operator=(const ref_base&)     {         return *this;     }      ref_base& operator=(ref_base&&)     {         return *this;     }   private :         uintptr_t inc_ref()     {         ++ref_count;         return ref_count.load();         }      uintptr_t dec_ref()     {         --ref_count;         return ref_count.load();     }      long use_count()     {         return ref_count.load();     }      atomic<uintptr_t> ref_count; };  class test : public ref_base {     public :      test()      {}      ~test()      {          cout << "~test()" << endl;      }  };  class test2 { public :     test2()     {}      ~test2()     {         cout << "~test2()" << endl;     } };  template <typename T, T TNul = T(), bool pseudo = false> class UniqueHandle { public:      UniqueHandle(std::nullptr_t = nullptr)         :m_id(TNul)     { }      UniqueHandle(T x)         :m_id(x)     {         // if file handle but not process or thread one prevent -1         if (!pseudo && m_id == INVALID_HANDLE_VALUE)             m_id = TNul;     }     explicit operator bool() const { return m_id != TNul; }      operator T&() { return m_id; }     operator T() const { return m_id; }      T *operator&() { return &m_id; }     const T *operator&() const { return &m_id; }      friend bool operator == (UniqueHandle a, UniqueHandle b) { return a.m_id == b.m_id; }     friend bool operator != (UniqueHandle a, UniqueHandle b) { return a.m_id != b.m_id; }     friend bool operator == (UniqueHandle a, std::nullptr_t) { return a.m_id == TNul; }     friend bool operator != (UniqueHandle a, std::nullptr_t) { return a.m_id != TNul; }     friend bool operator == (std::nullptr_t, UniqueHandle b) { return TNul == b.m_id; }     friend bool operator != (std::nullptr_t, UniqueHandle b) { return TNul != b.m_id; }  private:     T m_id; };  template <class HandleType, class DeleterType, DeleterType Deleter, HandleType null_handle = HandleType(), bool pseudo = false> struct UniqueHandleDeleter {     using pointer = UniqueHandle<HandleType, null_handle, pseudo>;     void operator()(pointer handle)     {         if (pseudo)         {             // pseudo handle is valid but isn't to be closed             if (handle == pointer(GetCurrentProcess()))                 return;         }         Deleter(handle);     } };  using SHandle = sp<int, UniqueHandleDeleter < HANDLE, decltype(&CloseHandle), CloseHandle>>; using SProcHandle = sp<int, UniqueHandleDeleter<HANDLE, decltype(&CloseHandle), CloseHandle, nullptr, true>>; using SRegHandle = sp<int, UniqueHandleDeleter<HKEY, decltype(&RegCloseKey), RegCloseKey>>; using SSocket = sp<int, UniqueHandleDeleter<SOCKET, decltype(&closesocket), closesocket, -1>>;