Skip to content

Instantly share code, notes, and snippets.

@Nekrolm
Created October 13, 2019 15:43
Show Gist options
  • Save Nekrolm/f3eba64b17e949dede3a5e3aafb90784 to your computer and use it in GitHub Desktop.
Save Nekrolm/f3eba64b17e949dede3a5e3aafb90784 to your computer and use it in GitHub Desktop.
#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