std::shared_ptr does not stop you from having the same resource managed by multiple control-blocks (and thus independent sets of shared-pointers), even though it is illegal and leads to double-deletes. Additionally, atomic reference-counts don't have any advantage in single-threaded environments but are still more expensive. Thus I wrote the following version to avoid these problems.
(This is a follow-up to: simple shared pointer implementation in single threaded environment)
template <typename T>
struct ThreadUnsafeSharedPtr {
private:
struct Pair {
T data;
size_t cnt;
template <typename ... Args>
Pair(Args && ... args): data(std::forward<Args>(args)...), cnt(1) {}
};
Pair *ptr;
public:
template <typename ... Args>
static ThreadUnsafeSharedPtr make(Args && ... args) {
ThreadUnsafeSharedPtr p;
p.ptr = new Pair(std::forward<Args>(args)...);
return p;
}
ThreadUnsafeSharedPtr() : ptr(nullptr) {}
ThreadUnsafeSharedPtr(const ThreadUnsafeSharedPtr & other) : ptr(other.ptr) {
if (ptr && &other != this) {
++(ptr->cnt);
}
}
ThreadUnsafeSharedPtr & operator=(const ThreadUnsafeSharedPtr & other) {
if (ptr && &other != this) {
ptr = other.ptr;
++(ptr->cnt);
}
return *this;
}
ThreadUnsafeSharedPtr(ThreadUnsafeSharedPtr && other) : ptr(other.ptr) {
if (&other != this) {
other.ptr = nullptr;
}
}
ThreadUnsafeSharedPtr & operator=(ThreadUnsafeSharedPtr && other) {
if (&other != this) {
ptr = other.ptr;
other.ptr = nullptr;
}
return *this;
}
~ThreadUnsafeSharedPtr() {
if (ptr) {
if(--ptr->cnt == 0) {
delete ptr;
}
}
}
T & operator* () {
return ptr->data;
}
T * operator-> () {
return &(ptr->data);
}
};
resourcefrom atomic to native type. \$\endgroup\$