/* * Copyright (C) 2014 Cloudius Systems, Ltd. */ #ifndef SHARED_PTR_HH_ #define SHARED_PTR_HH_ #include template class shared_ptr; template shared_ptr make_shared(A&&... a); template shared_ptr make_shared(T&& a); template shared_ptr make_shared(T& a); template class shared_ptr { struct data { long _count = 0; T _value; data() = default; data(const T& x) : _value(x) {} data(T&& x) : _value(std::move(x)) {} template data(A&&... a) : _value(std::forward(a)...) {} }; mutable data* _p = nullptr; private: explicit shared_ptr(data* p) : _p(p) { if (_p) { ++_p->_count; } } template static shared_ptr make(A&&... a) { return shared_ptr(new data(std::forward(a)...)); } public: shared_ptr() = default; shared_ptr(const shared_ptr& x) : _p(x._p) { if (_p) { ++_p->_count; } } shared_ptr(shared_ptr&& x) : _p(x._p) { x._p = nullptr; } ~shared_ptr() { if (_p && !--_p->_count) { delete _p; } } shared_ptr& operator=(const shared_ptr& x) { if (_p != x._p) { this->~shared_ptr(); new (this) shared_ptr(x); } return *this; } shared_ptr& operator=(shared_ptr&& x) { if (_p != x._p) { this->~shared_ptr(); new (this) shared_ptr(std::move(x)); } return *this; } shared_ptr& operator=(T&& x) { this->~shared_ptr(); new (this) shared_ptr(new data(std::move(x))); return *this; } T& operator*() const { return _p->_value; } T* operator->() const { return &_p->_value; } T* get() const { return &_p->_value; } long int use_count() { if (_p) { return _p->_count; } else { return 0; } } operator shared_ptr() const { return shared_ptr(_p); } explicit operator bool() const { return _p; } bool owned() const { return _p->_count == 1; } template friend shared_ptr make_shared(A&&...); template friend shared_ptr make_shared(U&&); template friend shared_ptr make_shared(U&); }; template inline shared_ptr make_shared(A&&... a) { return shared_ptr::make(std::forward(a)...); } template inline shared_ptr make_shared(T&& a) { return shared_ptr::make(std::move(a)); } template inline shared_ptr make_shared(T& a) { return shared_ptr::make(a); } #endif /* SHARED_PTR_HH_ */