Instantly share code, notes, and snippets.
Created
October 13, 2019 15:43
-
Star
(0)
0
You must be signed in to star a gist -
Fork
(0)
0
You must be signed in to fork a gist
-
Save Nekrolm/f3eba64b17e949dede3a5e3aafb90784 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <type_traits> | |
#include <utility> | |
#include <cstddef> | |
#include <iostream> | |
template <class T> | |
class WeakPtr; | |
template <class T> | |
class SharedPtr{ | |
friend WeakPtr<T>; | |
struct RefCounter{ | |
std::aligned_storage_t<sizeof(T), alignof(T)> object_placeholder; | |
size_t counter = 1; | |
size_t weak_counter = 0; | |
template <class... Args> | |
RefCounter(Args&&... args){ | |
new (&object_placeholder) T(std::forward<Args>(args)...); | |
} | |
void dispose(){ | |
reinterpret_cast<T*>(&object_placeholder)->~T(); | |
} | |
}; | |
public: | |
template <class... Args> | |
static SharedPtr<T> make(Args&&... args){ | |
SharedPtr<T> ret; | |
ret.ptr = new RefCounter(std::forward<Args>(args)...); | |
return ret; | |
} | |
SharedPtr() = default; | |
SharedPtr(const SharedPtr<T>& other){ | |
ptr = other.ptr; | |
if (ptr) ptr->counter++; | |
} | |
~SharedPtr(){ | |
detach(); | |
} | |
SharedPtr(SharedPtr<T>&& other) noexcept{ | |
ptr = other.ptr; | |
other.ptr = nullptr; | |
} | |
SharedPtr(nullptr_t) { | |
ptr = nullptr; | |
} | |
SharedPtr<T>& operator = (SharedPtr<T>&& other) noexcept { | |
detach(); | |
ptr = other.ptr; | |
other.ptr = nullptr; | |
return *this; | |
} | |
SharedPtr<T>& operator = (const SharedPtr<T>& other){ | |
SharedPtr<T> temp(other); | |
*this = std::move(temp); | |
return *this; | |
} | |
T& operator * () const{ | |
return *reinterpret_cast<T*>(ptr); | |
} | |
inline T* operator -> () const { | |
return reinterpret_cast<T*>(ptr); | |
} | |
inline T* get() const{ | |
return reinterpret_cast<T*>(ptr); | |
} | |
bool operator == (const SharedPtr<T>& other){ | |
return ptr == other.ptr; | |
} | |
bool operator == (nullptr_t){ | |
return ptr == nullptr; | |
} | |
size_t use_count() const{ | |
return ptr ? ptr->counter : 0; | |
} | |
private: | |
SharedPtr(RefCounter* counter){ | |
if (counter == nullptr) return; | |
if (counter->counter == 0) return; | |
ptr = counter; | |
ptr->counter++; | |
} | |
inline void detach(){ | |
if (!ptr) return; | |
if (--(ptr->counter) == 0){ | |
ptr->dispose(); | |
if (ptr->weak_counter == 0) | |
delete ptr; | |
} | |
ptr = nullptr; | |
} | |
RefCounter* ptr = nullptr; | |
}; | |
template <class T> | |
class WeakPtr{ | |
public: | |
WeakPtr() = default; | |
~WeakPtr() { | |
detach(); | |
} | |
WeakPtr(const SharedPtr<T>& other){ | |
ptr = other.ptr; | |
if (ptr) ptr->weak_counter++; | |
} | |
WeakPtr(const WeakPtr<T>& other){ | |
ptr = other.ptr; | |
if (ptr) ptr->weak_counter++; | |
} | |
WeakPtr(WeakPtr<T>&& other){ | |
ptr = other.ptr; | |
other.ptr = nullptr; | |
} | |
WeakPtr<T>& operator = (WeakPtr<T>&& other) noexcept{ | |
detach(); | |
ptr = other.ptr; | |
other.ptr = nullptr; | |
return *this; | |
} | |
WeakPtr<T>& operator = (const WeakPtr<T>& other) { | |
WeakPtr<T> temp(other); | |
*this = std::move(temp); | |
return *this; | |
} | |
bool expired() const{ | |
return !ptr || ptr->counter == 0; | |
} | |
SharedPtr<T> lock() const{ | |
return SharedPtr<T>(ptr); | |
} | |
private: | |
void detach(){ | |
if (!ptr) return; | |
if (--(ptr->weak_counter) == 0 && ptr->counter == 0){ | |
delete ptr; | |
} | |
ptr = nullptr; | |
} | |
typename SharedPtr<T>::RefCounter* ptr = nullptr; | |
}; | |
struct Test { | |
~Test() { std::cout << "dctor!\n";} | |
Test(int val) : value(val) {} | |
int value; | |
}; | |
int main(){ | |
using PtrT = SharedPtr<Test>; | |
PtrT x = nullptr; | |
PtrT y = PtrT::make(6); | |
x = y; | |
WeakPtr<Test> weak = x; | |
std::cout << "weak created\n"; | |
std::cout << x->value << "\n"; | |
x = nullptr; | |
y = nullptr; | |
std::cout << "weak alive!\n"; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment