Skip to content

Instantly share code, notes, and snippets.

@goldsborough
Created October 27, 2015 23:49
Show Gist options
  • Save goldsborough/1640aed80a605df058a7 to your computer and use it in GitHub Desktop.
Save goldsborough/1640aed80a605df058a7 to your computer and use it in GitHub Desktop.
A smart shared-pointer class.
template<typename T>
class SharedPointer
{
public:
using size_t = std::size_t;
using pointer_t = T*;
using const_pointer_t = const T*;
using reference_t = T&;
using const_reference_t = const T&;
using deleter_t = std::function<void(pointer_t)>;
explicit SharedPointer(pointer_t pointer = nullptr,
const deleter_t& deleter = std::default_delete<T>()) noexcept
: _pointer(pointer)
, _delete(deleter)
, _count(new std::atomic<size_t>(1))
{ }
SharedPointer(const SharedPointer& other) noexcept
: _pointer(other._pointer)
, _delete(other._delete)
, _count(other._count)
{
++(*_count);
}
template<typename U>
SharedPointer(const SharedPointer<U>& other) noexcept
: _pointer(other._pointer)
, _delete(other._delete)
, _count(other._count)
{
++(*_count);
}
SharedPointer(SharedPointer&& other) noexcept
: SharedPointer()
{
swap(other);
}
template<typename U>
SharedPointer(SharedPointer<U>&& other) noexcept
: SharedPointer()
{
swap(other);
}
SharedPointer& operator=(SharedPointer other) noexcept
{
swap(other);
return *this;
}
template<typename U>
SharedPointer& operator=(SharedPointer<U> other) noexcept
{
swap(other);
return *this;
}
template<typename U>
void swap(SharedPointer<U>& other) noexcept
{
// Enable Argument-Dependent-Lookup (ADL)
using std::swap;
swap(_pointer, other._pointer);
swap(_delete, other._delete);
swap(_count, other._count);
}
template<typename U, typename V>
friend void swap(SharedPointer<U>& first, SharedPointer<V>& second) noexcept
{
first.swap(second);
}
~SharedPointer()
{
if (--(*_count) == 0)
{
_delete(_pointer);
delete _count;
}
}
reference_t operator*()
{
return *_pointer;
}
const_reference_t operator*() const
{
return *_pointer;
}
pointer_t operator->()
{
return _pointer;
}
const_pointer_t operator->() const
{
return _pointer;
}
template<typename U>
bool operator==(const SharedPointer<U>& other)
{
return _pointer == other._pointer;
}
template<typename U>
bool operator!=(const SharedPointer<U>& other)
{
return _pointer != other._pointer;
}
template<typename U>
bool operator<=(const SharedPointer<U>& other)
{
return _pointer <= other._pointer;
}
template<typename U>
bool operator>=(const SharedPointer<U>& other)
{
return _pointer >= other._pointer;
}
template<typename U>
bool operator<(const SharedPointer<U>& other)
{
return _pointer < other._pointer;
}
template<typename U>
bool operator>(const SharedPointer<U>& other)
{
return _pointer > other._pointer;
}
operator bool()
{
return _pointer != nullptr;
}
pointer_t get()
{
return _pointer;
}
const_pointer_t get() const
{
return _pointer;
}
pointer_t release()
{
auto pointer = _pointer;
_pointer = nullptr;
return pointer;
}
void reset(pointer_t new_pointer = nullptr)
{
auto count = _count->load();
// Then it would now be 0, but we can keep the 1
// stored in the pointer for efficiency
if (count == 1) _delete(_pointer);
else
{
_count->store(count - 1);
_count = new std::atomic<size_t>(1);
}
_pointer = new_pointer;
}
size_t count() const
{
return _count->load();
}
private:
pointer_t _pointer;
deleter_t _delete;
std::atomic<size_t>* _count;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment