I am implementing my own double-indirecting shared-ownership smart-pointer because I needed a way to replace the managed object a group of smart-pointers is pointing to with a new object (it's the method reset_all
in the code below).
I tried to keep this as close as I could to the std::shared_ptr
's interface, while avoiding things I don't understand / need like aliasing and conversion from other smart-pointer types.
//(it's all in an header file)
#pragma once
template <typename T>
class Manager {
template <typename U>
friend class SharedPtr;
T* managed;
unsigned int counter;
Manager(T* new_ptr):
managed(new_ptr), counter(1) {}
~Manager() = default;
Manager<T>* own() {
++counter;
return this;
}
void disown() {
if (!(--counter)) {
delete managed;
delete this;
}
}
};
template <typename T>
class SharedPtr {
public:
SharedPtr() = default;
SharedPtr(T* new_ptr) {
if (new_ptr) {
manager = new Manager<T>(new_ptr);
}
}
SharedPtr(const SharedPtr &rhs):
manager(rhs.manager->own()) {}
SharedPtr(SharedPtr &&rhs):
manager(rhs.manager) {
rhs.manager = nullptr;
}
SharedPtr& operator=(const SharedPtr &rhs) {
if (manager) {
manager->disown();
}
manager = rhs.manager->own();
return *this;
}
SharedPtr& operator=(SharedPtr &&rhs) {
if (manager) {
manager->disown();
}
manager = rhs.manager;
rhs.manager = nullptr;
return *this;
}
void swap(SharedPtr &rhs) {
Manager<T>* tmp = manager;
manager = rhs.manager;
rhs.manager = tmp;
}
void reset() {
if (manager) {
manager->disown();
}
manager = nullptr;
}
void reset(T* new_ptr) {
if (manager) {
manager->disown();
}
manager = new Manager<T>(new_ptr);
}
T* get() {
if (manager) {
return manager->managed;
}
return nullptr;
}
T& operator*() {
return *(manager->managed);
}
T* operator->() {
return manager->managed;
}
unsigned int use_count() {
if (manager) {
return manager->counter;
}
return 0;
}
bool unique() {
return use_count() == 1;
}
operator bool() {
return (bool) manager;
}
void reset_all(T* new_ptr) {
if (manager) {
delete manager->managed;
manager->managed = new_ptr;
return;
}
manager = new Manager<T>(new_ptr);
}
~SharedPtr() {
if (manager) {
manager->disown();
}
}
private:
Manager<T>* manager = nullptr;
};