I reinvented a c++ smart pointer, shared_ptr
to be precise. It is meant for practice purpose and does not attempt to replace the standard implementation. To the best of my knowledge, the code works as expected. I decided to skip the custom deleter because I want to keep things simple for now. I would love feedbacks and constructive criticism.
Here is the implementation
shared.hpp
#ifndef SHARED_PTR_H_
#define SHARED_PTR_H_
#include <cstddef>
namespace smp
{
template<typename T>
class shared_ptr
{
public:
explicit shared_ptr(T* ptr = nullptr);
~shared_ptr();
shared_ptr(shared_ptr& ptr);
shared_ptr operator=(shared_ptr& ptr);
shared_ptr(shared_ptr&& ptr) noexcept;
shared_ptr operator=(shared_ptr&& ptr) noexcept;
T operator*();
T* operator->() const;
size_t use_count() const;
void reset();
T* get();
bool unique() const;
operator bool() const;
private:
T* obj_ptr;
struct RefCount {
size_t use_count_;
T* object_;
}* ref_cnt;
};
template<typename T>
shared_ptr<T> make_shared(T object);
}
#endif /* SHARED_PTR_H_ */
shared.cpp
#include "shared.hpp"
#include <algorithm>
#include <iostream>
namespace smp
{
template<typename T>
shared_ptr<T>::shared_ptr(T* ptr)
: obj_ptr{ptr}, ref_cnt{new RefCount()}
{
ref_cnt->object_ = ptr;
if(ptr)
++ref_cnt->use_count_;
}
template<typename T>
shared_ptr<T>::shared_ptr(shared_ptr& ptr)
: ref_cnt{new RefCount()}
{
obj_ptr = ptr.obj_ptr;
ref_cnt = ptr.ref_cnt;
++ref_cnt->use_count_;
}
template<typename T>
shared_ptr<T> shared_ptr<T>::operator=(shared_ptr& ptr)
{
obj_ptr = ptr.obj_ptr;
ref_cnt = ptr.ref_cnt;
++ref_cnt->use_count_;
return *this;
}
template<typename T>
shared_ptr<T>::shared_ptr(shared_ptr&& ptr) noexcept
: obj_ptr{nullptr}, ref_cnt{new RefCount()}
{
obj_ptr = std::move(ptr.obj_ptr);
ref_cnt = std::move(ptr.ref_cnt);
ptr.reset();
}
template<typename T>
shared_ptr<T> shared_ptr<T>::operator=(shared_ptr&& ptr) noexcept
{
if(obj_ptr)
reset();
obj_ptr = std::move(ptr.obj_ptr);
ref_cnt = std::move(ptr.ref_cnt);
ptr.obj_ptr = nullptr;
return *this;
}
template<typename T>
shared_ptr<T> make_shared(T object)
{
return shared_ptr<T>(new T{object});
}
template<typename T>
T shared_ptr<T>::operator*()
{
return *obj_ptr;
}
template<typename T>
T* shared_ptr<T>::operator->() const
{
return &*obj_ptr;
}
template<typename T>
size_t shared_ptr<T>::use_count() const
{
return ref_cnt->use_count_;
}
template<typename T>
void shared_ptr<T>::reset()
{
obj_ptr = nullptr;
if(ref_cnt)
--ref_cnt->use_count_;
if(ref_cnt->use_count_ == 0)
ref_cnt->object_->~T();
}
template<typename T>
T* shared_ptr<T>::get()
{
return obj_ptr;
}
template<typename T>
bool shared_ptr<T>::unique() const
{
return (ref_cnt->use_count_ == 1);
}
template<typename T>
shared_ptr<T>::operator bool() const
{
return (obj_ptr != nullptr);
}
template<typename T>
shared_ptr<T>::~shared_ptr()
{
if(obj_ptr)
reset();
}
}