Require explicit copies for Ref/WeakRef

This commit is contained in:
2025-09-12 11:59:56 -04:00
parent 674ff581e7
commit f89868058a
4 changed files with 145 additions and 162 deletions

View File

@@ -22,8 +22,8 @@
* Basic usage:
* @code
* auto obj = make_ref<MyClass>(args...); // Create managed object
* auto copy = obj; // Copy (thread-safe)
* WeakRef<MyClass> weak = obj; // Create weak reference
* auto copy = obj.copy(); // Explicit copy (thread-safe)
* WeakRef<MyClass> weak = obj.as_weak(); // Create weak reference
* auto locked = weak.lock(); // Try to promote to strong
* @endcode
*
@@ -31,6 +31,9 @@
* safely copy, move, and destroy references to the same object.
*/
// Forward declaration
template <typename T> struct WeakRef;
namespace detail {
struct ControlBlock {
std::atomic<uint32_t> strong_count;
@@ -126,57 +129,28 @@ template <typename T> struct Ref {
~Ref() { release(); }
/**
* @brief Copy constructor - increments strong reference count
* @brief Copy constructor - deleted to prevent accidental copies
* Use copy() method for explicit copying
*/
Ref(const Ref &other) noexcept
: ptr(other.ptr), control_block(other.control_block) {
if (control_block) {
control_block->increment_strong();
}
}
Ref(const Ref &other) = delete;
/**
* @brief Converting copy constructor for polymorphism (Derived -> Base)
* @brief Converting copy constructor - deleted to prevent accidental copies
* Use copy() method for explicit copying
*/
template <typename U>
Ref(const Ref<U> &other) noexcept
requires std::is_convertible_v<U *, T *>
: ptr(other.ptr), control_block(other.control_block) {
if (control_block) {
control_block->increment_strong();
}
}
template <typename U> Ref(const Ref<U> &other) = delete;
/**
* @brief Copy assignment operator
* @brief Copy assignment operator - deleted to prevent accidental copies
* Use copy() method for explicit copying
*/
Ref &operator=(const Ref &other) noexcept {
if (this != &other) {
release();
ptr = other.ptr;
control_block = other.control_block;
if (control_block) {
control_block->increment_strong();
}
}
return *this;
}
Ref &operator=(const Ref &other) = delete;
/**
* @brief Converting assignment operator for polymorphism (Derived -> Base)
* @brief Converting assignment operator - deleted to prevent accidental
* copies Use copy() method for explicit copying
*/
template <typename U>
Ref &operator=(const Ref<U> &other) noexcept
requires std::is_convertible_v<U *, T *>
{
release();
ptr = other.ptr;
control_block = other.control_block;
if (control_block) {
control_block->increment_strong();
}
return *this;
}
template <typename U> Ref &operator=(const Ref<U> &other) = delete;
/**
* @brief Move constructor - transfers ownership
@@ -228,6 +202,28 @@ template <typename T> struct Ref {
return *this;
}
/**
* @brief Explicitly create a copy with shared ownership
* @return New Ref that shares ownership of the same object
*/
[[nodiscard]] Ref copy() const noexcept {
if (control_block) {
control_block->increment_strong();
}
return Ref(ptr, control_block);
}
/**
* @brief Create a WeakRef that observes this object
* @return New WeakRef that observes the same object
*/
[[nodiscard]] WeakRef<T> as_weak() const noexcept {
if (control_block) {
control_block->increment_weak();
}
return WeakRef<T>(control_block);
}
/**
* @brief Reset to empty state
*/
@@ -347,76 +343,40 @@ template <typename T> struct WeakRef {
~WeakRef() { release(); }
/**
* @brief Copy constructor from WeakRef
* @brief Copy constructor from WeakRef - deleted to prevent accidental copies
* Use copy() method for explicit copying
*/
WeakRef(const WeakRef &other) noexcept : control_block(other.control_block) {
if (control_block) {
control_block->increment_weak();
}
}
WeakRef(const WeakRef &other) = delete;
/**
* @brief Copy constructor from Ref
* @brief Copy constructor from Ref - deleted to prevent accidental copies
* Use copy() method for explicit copying
*/
WeakRef(const Ref<T> &ref) noexcept : control_block(ref.control_block) {
if (control_block) {
control_block->increment_weak();
}
}
WeakRef(const Ref<T> &ref) = delete;
/**
* @brief Converting copy constructor from WeakRef for polymorphism
* @brief Converting copy constructor from WeakRef - deleted to prevent
* accidental copies Use copy() method for explicit copying
*/
template <typename U>
WeakRef(const WeakRef<U> &other) noexcept
requires std::is_convertible_v<U *, T *>
: control_block(other.control_block) {
if (control_block) {
control_block->increment_weak();
}
}
template <typename U> WeakRef(const WeakRef<U> &other) = delete;
/**
* @brief Converting copy constructor from Ref for polymorphism
* @brief Converting copy constructor from Ref - deleted to prevent accidental
* copies Use copy() method for explicit copying
*/
template <typename U>
WeakRef(const Ref<U> &ref) noexcept
requires std::is_convertible_v<U *, T *>
: control_block(ref.control_block) {
if (control_block) {
control_block->increment_weak();
}
}
template <typename U> WeakRef(const Ref<U> &ref) = delete;
/**
* @brief Converting copy assignment from WeakRef for polymorphism
* @brief Converting copy assignment from WeakRef - deleted to prevent
* accidental copies Use copy() method for explicit copying
*/
template <typename U>
WeakRef &operator=(const WeakRef<U> &other) noexcept
requires std::is_convertible_v<U *, T *>
{
release();
control_block = other.control_block;
if (control_block) {
control_block->increment_weak();
}
return *this;
}
template <typename U> WeakRef &operator=(const WeakRef<U> &other) = delete;
/**
* @brief Converting copy assignment from Ref for polymorphism
* @brief Converting copy assignment from Ref - deleted to prevent accidental
* copies Use copy() method for explicit copying
*/
template <typename U>
WeakRef &operator=(const Ref<U> &ref) noexcept
requires std::is_convertible_v<U *, T *>
{
release();
control_block = ref.control_block;
if (control_block) {
control_block->increment_weak();
}
return *this;
}
template <typename U> WeakRef &operator=(const Ref<U> &ref) = delete;
/**
* @brief Converting move constructor from WeakRef for polymorphism
@@ -442,30 +402,16 @@ template <typename T> struct WeakRef {
}
/**
* @brief Copy assignment from WeakRef
* @brief Copy assignment from WeakRef - deleted to prevent accidental copies
* Use copy() method for explicit copying
*/
WeakRef &operator=(const WeakRef &other) noexcept {
if (this != &other) {
release();
control_block = other.control_block;
if (control_block) {
control_block->increment_weak();
}
}
return *this;
}
WeakRef &operator=(const WeakRef &other) = delete;
/**
* @brief Copy assignment from Ref
* @brief Copy assignment from Ref - deleted to prevent accidental copies
* Use copy() method for explicit copying
*/
WeakRef &operator=(const Ref<T> &ref) noexcept {
release();
control_block = ref.control_block;
if (control_block) {
control_block->increment_weak();
}
return *this;
}
WeakRef &operator=(const Ref<T> &ref) = delete;
/**
* @brief Move constructor
@@ -486,6 +432,17 @@ template <typename T> struct WeakRef {
return *this;
}
/**
* @brief Explicitly create a copy with shared weak reference
* @return New WeakRef that observes the same object
*/
[[nodiscard]] WeakRef copy() const noexcept {
if (control_block) {
control_block->increment_weak();
}
return WeakRef(control_block);
}
/**
* @brief Reset to empty state
*/
@@ -550,6 +507,8 @@ private:
* @code
* auto obj = make_ref<MyClass>(arg1, arg2);
* auto empty_vec = make_ref<std::vector<int>>();
* auto obj_copy = obj.copy(); // Explicit copy
* WeakRef<MyClass> weak = obj.as_weak(); // Create weak reference
* @endcode
*
* Thread safety: Safe to call from multiple threads simultaneously.

View File

@@ -25,7 +25,7 @@ Ref<Server> Server::create(const weaseldb::Config &config,
ConnectionHandler &handler,
const std::vector<int> &listen_fds) {
auto result = make_ref<Server>(config, handler, listen_fds);
result->self_ = result;
result->self_ = result.as_weak();
return result;
}
@@ -218,7 +218,7 @@ int Server::create_local_connection() {
// Create Connection object
auto connection = std::unique_ptr<Connection>(new Connection(
addr, server_fd, connection_id_.fetch_add(1, std::memory_order_relaxed),
epoll_index, &handler_, self_));
epoll_index, &handler_, self_.copy()));
// Store in registry
connection_registry_.store(server_fd, std::move(connection));
@@ -422,7 +422,7 @@ void Server::start_io_threads(std::vector<std::thread> &threads) {
batch[batch_count] = std::unique_ptr<Connection>(new Connection(
addr, fd,
connection_id_.fetch_add(1, std::memory_order_relaxed),
epoll_index, &handler_, self_));
epoll_index, &handler_, self_.copy()));
batch_events[batch_count] =
EPOLLIN; // New connections always start with read
batch_count++;