refactor: modernize SmartPointer with thread-safe reference counting, move semantics, and custom deleter support, and add corresponding unit test.
This commit is contained in:
@@ -23,89 +23,239 @@
|
|||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef U_CORE_SMARTPOINTER_H
|
#ifndef U_CORE_SMARTPOINTER_H
|
||||||
#define U_CORE_SMARTPOINTER_H
|
#define U_CORE_SMARTPOINTER_H
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <functional>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
namespace uLib {
|
namespace uLib {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A smart pointer implementation inspired by std::shared_ptr.
|
||||||
|
*
|
||||||
|
* Features modernized C++11/14/17 syntax, thread-safe reference counting,
|
||||||
|
* move semantics, and support for custom deleters.
|
||||||
|
*
|
||||||
|
* NOTE: Default constructor allocates a new T following legacy behavior.
|
||||||
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class SmartPointer {
|
class SmartPointer {
|
||||||
typedef T element_type;
|
|
||||||
public:
|
public:
|
||||||
|
using element_type = T;
|
||||||
|
|
||||||
explicit
|
/**
|
||||||
SmartPointer(T* ptr = NULL) : m_counter(0) {
|
* @brief Constructor from raw pointer.
|
||||||
if(!ptr) ptr = new T;
|
* If ptr is nullptr, a new T is allocated (legacy behavior).
|
||||||
|
*/
|
||||||
|
explicit SmartPointer(T* ptr = nullptr) : m_counter(nullptr) {
|
||||||
|
if (!ptr) ptr = new T();
|
||||||
if (ptr) m_counter = new ReferenceCounter(ptr);
|
if (ptr) m_counter = new ReferenceCounter(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TakeReference //
|
/**
|
||||||
SmartPointer(T &ref) : m_counter(new ReferenceCounter(&ref,0)) { }
|
* @brief Constructor with custom deleter.
|
||||||
|
*/
|
||||||
SmartPointer(const SmartPointer& copy) throw () {
|
template <typename D>
|
||||||
acquire(copy.m_counter);
|
SmartPointer(T* ptr, D deleter) : m_counter(nullptr) {
|
||||||
|
if (ptr) m_counter = new ReferenceCounter(ptr, deleter);
|
||||||
}
|
}
|
||||||
|
|
||||||
SmartPointer(SmartPointer * copy) throw () {
|
/**
|
||||||
acquire(copy->m_counter);
|
* @brief Non-owning constructor from reference.
|
||||||
|
* Uses a no-op deleter to ensure the referenced object is not destroyed.
|
||||||
|
*/
|
||||||
|
SmartPointer(T &ref) : m_counter(new ReferenceCounter(&ref, [](T*){}, 1)) { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Copy constructor.
|
||||||
|
*/
|
||||||
|
SmartPointer(const SmartPointer& other) noexcept : m_counter(nullptr) {
|
||||||
|
acquire(other.m_counter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Copy constructor from a pointer to SmartPointer (Legacy support).
|
||||||
|
*/
|
||||||
|
SmartPointer(const SmartPointer* other) noexcept : m_counter(nullptr) {
|
||||||
|
if (other) acquire(other->m_counter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Move constructor.
|
||||||
|
*/
|
||||||
|
SmartPointer(SmartPointer&& other) noexcept : m_counter(other.m_counter) {
|
||||||
|
other.m_counter = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Virtual destructor.
|
||||||
|
*/
|
||||||
virtual ~SmartPointer() { release(); }
|
virtual ~SmartPointer() { release(); }
|
||||||
|
|
||||||
SmartPointer & operator=(const SmartPointer& copy) {
|
/**
|
||||||
if (this != ©)
|
* @brief Copy assignment.
|
||||||
{
|
*/
|
||||||
|
SmartPointer& operator=(const SmartPointer& other) noexcept {
|
||||||
|
if (this != &other) {
|
||||||
release();
|
release();
|
||||||
acquire(copy.m_counter);
|
acquire(other.m_counter);
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
T & operator*() const throw () { return *m_counter->ptr; }
|
/**
|
||||||
T * operator->() const throw () { return m_counter->ptr; }
|
* @brief Move assignment.
|
||||||
|
*/
|
||||||
|
SmartPointer& operator=(SmartPointer&& other) noexcept {
|
||||||
|
if (this != &other) {
|
||||||
|
release();
|
||||||
|
m_counter = other.m_counter;
|
||||||
|
other.m_counter = nullptr;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
T * get() const throw () {
|
/**
|
||||||
return m_counter ? m_counter->ptr : 0; }
|
* @brief Resets the smart pointer to hold a new raw pointer.
|
||||||
bool unique() const throw () {
|
*/
|
||||||
return (m_counter ? m_counter->count == 1 : true); }
|
void reset(T* ptr = nullptr) {
|
||||||
|
release();
|
||||||
|
if (ptr) m_counter = new ReferenceCounter(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Resets the smart pointer with a custom deleter.
|
||||||
|
*/
|
||||||
|
template <typename D>
|
||||||
|
void reset(T* ptr, D deleter) {
|
||||||
|
release();
|
||||||
|
if (ptr) m_counter = new ReferenceCounter(ptr, deleter);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
/**
|
||||||
|
* @brief Swaps contents with another SmartPointer.
|
||||||
|
*/
|
||||||
|
void swap(SmartPointer& other) noexcept {
|
||||||
|
std::swap(m_counter, other.m_counter);
|
||||||
|
}
|
||||||
|
|
||||||
struct ReferenceCounter
|
/**
|
||||||
{
|
* @brief Dereference operator.
|
||||||
ReferenceCounter(T* ptr = 0, unsigned c = 1) : ptr(ptr), count(c) { }
|
*/
|
||||||
|
T& operator*() const noexcept { return *m_counter->ptr; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Member access operator.
|
||||||
|
*/
|
||||||
|
T* operator->() const noexcept { return m_counter->ptr; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the raw pointer.
|
||||||
|
*/
|
||||||
|
T* get() const noexcept { return m_counter ? m_counter->ptr : nullptr; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the number of SmartPointers sharing ownership.
|
||||||
|
*/
|
||||||
|
uint32_t use_count() const noexcept {
|
||||||
|
return m_counter ? m_counter->count.load(std::memory_order_relaxed) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns true if this is the only SmartPointer owning the resource.
|
||||||
|
*/
|
||||||
|
bool unique() const noexcept { return use_count() == 1; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Boolean conversion operator.
|
||||||
|
*/
|
||||||
|
explicit operator bool() const noexcept { return get() != nullptr; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct ReferenceCounter {
|
||||||
T* ptr;
|
T* ptr;
|
||||||
unsigned count;
|
std::atomic<uint32_t> count;
|
||||||
} * m_counter;
|
std::function<void(T*)> deleter;
|
||||||
|
|
||||||
// increment the count
|
ReferenceCounter(T* p, uint32_t initial_count = 1)
|
||||||
void acquire(ReferenceCounter* c) throw ()
|
: ptr(p), count(initial_count), deleter([](T* ptr_to_del) { delete ptr_to_del; }) {}
|
||||||
{
|
|
||||||
|
template <typename D>
|
||||||
|
ReferenceCounter(T* p, D d, uint32_t initial_count = 1)
|
||||||
|
: ptr(p), count(initial_count), deleter(d) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
ReferenceCounter* m_counter;
|
||||||
|
|
||||||
|
void acquire(ReferenceCounter* c) noexcept {
|
||||||
m_counter = c;
|
m_counter = c;
|
||||||
if (c && c->count>0) ++c->count;
|
if (c) {
|
||||||
|
c->count.fetch_add(1, std::memory_order_relaxed);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// decrement the count, delete if it is 0
|
void release() noexcept {
|
||||||
void release() {
|
|
||||||
if (m_counter) {
|
if (m_counter) {
|
||||||
if (--m_counter->count == 0) {
|
if (m_counter->count.fetch_sub(1, std::memory_order_acq_rel) == 1) {
|
||||||
delete m_counter->ptr;
|
if (m_counter->ptr) {
|
||||||
|
m_counter->deleter(m_counter->ptr);
|
||||||
}
|
}
|
||||||
if (m_counter->count <= 0) {
|
|
||||||
delete m_counter;
|
delete m_counter;
|
||||||
m_counter = NULL;
|
}
|
||||||
|
m_counter = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Global swap for SmartPointer.
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
void swap(SmartPointer<T>& a, SmartPointer<T>& b) noexcept {
|
||||||
|
a.swap(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // SMARTPOINTER_H
|
/**
|
||||||
|
* @brief Equality comparison.
|
||||||
|
*/
|
||||||
|
template <typename T, typename U>
|
||||||
|
bool operator==(const SmartPointer<T>& a, const SmartPointer<U>& b) noexcept {
|
||||||
|
return a.get() == b.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Inequality comparison.
|
||||||
|
*/
|
||||||
|
template <typename T, typename U>
|
||||||
|
bool operator!=(const SmartPointer<T>& a, const SmartPointer<U>& b) noexcept {
|
||||||
|
return a.get() != b.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Comparison with nullptr.
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
bool operator==(const SmartPointer<T>& a, std::nullptr_t) noexcept {
|
||||||
|
return a.get() == nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool operator==(std::nullptr_t, const SmartPointer<T>& a) noexcept {
|
||||||
|
return a.get() == nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool operator!=(const SmartPointer<T>& a, std::nullptr_t) noexcept {
|
||||||
|
return a.get() != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool operator!=(std::nullptr_t, const SmartPointer<T>& a) noexcept {
|
||||||
|
return a.get() != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace uLib
|
||||||
|
|
||||||
|
#endif // U_CORE_SMARTPOINTER_H
|
||||||
|
|||||||
@@ -139,7 +139,6 @@ typedef id_t Id_t;
|
|||||||
typedef void *Pointer_t;
|
typedef void *Pointer_t;
|
||||||
typedef bool Bool_t; // Boolean (0=false, 1=true) (bool)
|
typedef bool Bool_t; // Boolean (0=false, 1=true) (bool)
|
||||||
|
|
||||||
|
|
||||||
//--- bit manipulation ---------------------------------------------------------
|
//--- bit manipulation ---------------------------------------------------------
|
||||||
#ifndef BIT
|
#ifndef BIT
|
||||||
#define BIT(n) (1ULL << (n))
|
#define BIT(n) (1ULL << (n))
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
# TESTS
|
# TESTS
|
||||||
set( TESTS
|
set( TESTS
|
||||||
SmartVectorTest
|
SmartVectorTest
|
||||||
|
SmartPointerTest
|
||||||
VectorTest
|
VectorTest
|
||||||
ObjectFlagsTest
|
ObjectFlagsTest
|
||||||
ObjectParametersTest
|
ObjectParametersTest
|
||||||
|
|||||||
Reference in New Issue
Block a user