#include<iostream> #include<atomic> using namespace std; template <typename T> class SharedPtr { private: T* ptr; std::atomic<int>* refCount; public: //Default Ctor SharedPtr() : ptr(nullptr), refCount(nullptr) {} SharedPtr(nullptr_t): SharedPtr(){} explicit SharedPtr(T* rawPtr) : ptr(rawPtr), refCount(new std::atomic<int>(1)) {} template <typename U> explicit SharedPtr(U* rawPtr) : ptr(rawPtr), refCount(new std::atomic<int>(1)) {} //Copy Ctor SharedPtr(const SharedPtr& other) : ptr(other.ptr), refCount(other.refCount) { if (ptr) (*refCount).fetch_add(1, std::memory_order_relaxed); } template <typename U> // How this works if it works?? SharedPtr(const SharedPtr<U>& other) : ptr(other.get()), refCount(other.getRefCount()) { if (ptr) { (*refCount).fetch_add(1, std::memory_order_relaxed); } } //Copy Assignment SharedPtr& operator=(const SharedPtr& other) { if (this != &other) { swap(*this,SharedPtr(other)); /*release(); ptr = other.ptr; refCount = other.refCount; if (ptr) { (*refCount).fetch_add(1, std::memory_order_relaxed); }*/ } return *this; } template <typename U> SharedPtr& operator=(const SharedPtr<U>& other) { if (this != &other) { swap(*this,SharedPtr(other)); /*release(); ptr = other.ptr; refCount = other.refCount; if (ptr) { (*refCount).fetch_add(1, std::memory_order_relaxed); }*/ } return *this; } // Move Ctors SharedPtr(SharedPtr&& other) noexcept : SharedPtr() {swap(*this, other);} template <typename U> SharedPtr(SharedPtr<U>&& other) noexcept : SharedPtr() {swap(*this, other);} //Move Assignment SharedPtr& operator=(SharedPtr&& other) noexcept { if (this != &other) { release(); ptr = other.ptr; refCount = other.refCount;//swap(*this, other); other.ptr = nullptr; other.refCount = nullptr; } return *this; } template <typename U> SharedPtr& operator=(SharedPtr<U>&& other) noexcept { release(); //swap(*this, other); ptr = other.get(); refCount = other.getRefCount(); other.resetToNull(); return *this; } ~SharedPtr() { release();} T& operator*() const {return *ptr;} T* operator->() const { return ptr; } int use_count() const { return refCount ? refCount->load(std::memory_order_acquire) : 0;} T* get() const { return ptr;} std::atomic<int>* getRefCount() const { return refCount; } bool unique() const { return use_count() == 1;} void resetToNull() { ptr = nullptr; refCount = nullptr; } void reset(T* rawPtr) { release(); ptr = rawPtr; if (ptr) refCount = new std::atomic<int>(1); else refCount = nullptr; } void swap(SharedPtr& lhs, SharedPtr& rhs) noexcept { std::swap(lhs.ptr, rhs.ptr); std::swap(lhs.refCount, rhs.refCount); } void swap(SharedPtr& lhs, SharedPtr&& rhs) noexcept { std::swap(lhs.ptr, rhs.ptr); std::swap(lhs.refCount, rhs.refCount); } void release() { if (ptr && refCount && (*refCount).fetch_sub(1, std::memory_order_release) == 1) { std::atomic_thread_fence(std::memory_order_acquire); delete ptr; delete refCount; } } }; template<typename T, typename... Args> SharedPtr<T> make_shared(Args&&... args) { return SharedPtr<T>(new T(std::forward<Args>(args)...)); } class Base { public: virtual void print() const { std::cout << "Base class\n"; } }; class Derived : public Base { public: void print() const override { std::cout << "Derived class\n"; } }; int main() { SharedPtr<Base> ptr1(new Base); SharedPtr<Base> ptrC(ptr1); SharedPtr<Base> ptr2(new Derived); SharedPtr<Derived> dtr1(new Derived); //SharedPtr<Base> mt1(dtr1); //SharedPtr<Base> ptr3(ptr2); std::cout << "dtr1 use count: " << dtr1.use_count() << "\n"; std::cout << "ptr1 use count: " << ptr1.use_count() << "\n"; std::cout << "ptr2 use count: " << ptr2.use_count() << "\n"; std::cout << "ptrC use count: " << ptrC.use_count() << "\n"; //ptr1 = std::move(ptr2); // or ptr1 = std::move(dtr1); std::cout<<"After\n"; std::cout << "dtr1 use count: " << dtr1.use_count() << "\n"; std::cout << "ptr1 use count: " << ptr1.use_count() << "\n"; std::cout << "ptr2 use count: " << ptr2.use_count() << "\n"; std::cout << "ptrC use count: " << ptrC.use_count() << "\n"; return 0; }