Require explicit copies for Ref/WeakRef
This commit is contained in:
@@ -52,9 +52,9 @@ TEST_CASE("Ref basic functionality") {
|
||||
CHECK((*ref).value == 42);
|
||||
}
|
||||
|
||||
SUBCASE("copy construction increments reference count") {
|
||||
SUBCASE("explicit copy increments reference count") {
|
||||
auto ref1 = make_ref<TestObject>(123);
|
||||
auto ref2 = ref1;
|
||||
auto ref2 = ref1.copy();
|
||||
|
||||
CHECK(ref1);
|
||||
CHECK(ref2);
|
||||
@@ -63,11 +63,11 @@ TEST_CASE("Ref basic functionality") {
|
||||
CHECK(ref2->value == 123);
|
||||
}
|
||||
|
||||
SUBCASE("copy assignment works correctly") {
|
||||
SUBCASE("explicit copy assignment works correctly") {
|
||||
auto ref1 = make_ref<TestObject>(100);
|
||||
auto ref2 = make_ref<TestObject>(200);
|
||||
|
||||
ref2 = ref1;
|
||||
ref2 = ref1.copy();
|
||||
CHECK(ref1.get() == ref2.get());
|
||||
CHECK(ref1->value == 100);
|
||||
CHECK(ref2->value == 100);
|
||||
@@ -109,7 +109,7 @@ TEST_CASE("Ref basic functionality") {
|
||||
TEST_CASE("WeakRef basic functionality") {
|
||||
SUBCASE("construction from Ref") {
|
||||
auto ref = make_ref<TestObject>(333);
|
||||
WeakRef<TestObject> weak_ref = ref;
|
||||
WeakRef<TestObject> weak_ref = ref.as_weak();
|
||||
|
||||
auto locked = weak_ref.lock();
|
||||
CHECK(locked);
|
||||
@@ -121,7 +121,7 @@ TEST_CASE("WeakRef basic functionality") {
|
||||
WeakRef<TestObject> weak_ref;
|
||||
{
|
||||
auto ref = make_ref<TestObject>(444);
|
||||
weak_ref = ref;
|
||||
weak_ref = ref.as_weak();
|
||||
}
|
||||
// ref goes out of scope, object should be destroyed
|
||||
|
||||
@@ -131,8 +131,8 @@ TEST_CASE("WeakRef basic functionality") {
|
||||
|
||||
SUBCASE("copy and move semantics") {
|
||||
auto ref = make_ref<TestObject>(666);
|
||||
WeakRef<TestObject> weak1 = ref;
|
||||
WeakRef<TestObject> weak2 = weak1; // copy
|
||||
WeakRef<TestObject> weak1 = ref.as_weak();
|
||||
WeakRef<TestObject> weak2 = weak1.copy(); // explicit copy
|
||||
WeakRef<TestObject> weak3 = std::move(weak1); // move
|
||||
|
||||
auto locked2 = weak2.lock();
|
||||
@@ -160,7 +160,7 @@ TEST_CASE("Ref thread safety") {
|
||||
start_latch.arrive_and_wait();
|
||||
|
||||
for (int j = 0; j < copies_per_thread; ++j) {
|
||||
auto copy = ref;
|
||||
auto copy = ref.copy();
|
||||
CHECK(copy);
|
||||
CHECK(copy->value == 777);
|
||||
}
|
||||
@@ -191,7 +191,7 @@ TEST_CASE("Control block cleanup race condition test") {
|
||||
WeakRef<TestObject> ptr2;
|
||||
auto setup = [&]() {
|
||||
ptr1 = make_ref<TestObject>(0);
|
||||
ptr2 = ptr1;
|
||||
ptr2 = ptr1.as_weak();
|
||||
};
|
||||
|
||||
// Barrier for synchronization - 2 participants (main thread + worker thread)
|
||||
@@ -243,7 +243,7 @@ TEST_CASE("WeakRef prevents circular references") {
|
||||
// Create object and weak reference
|
||||
{
|
||||
auto ref = make_ref<TestObject>(123);
|
||||
weak_ref = ref;
|
||||
weak_ref = ref.as_weak();
|
||||
|
||||
// Should be able to lock while object exists
|
||||
auto locked = weak_ref.lock();
|
||||
@@ -262,8 +262,8 @@ TEST_CASE("WeakRef prevents circular references") {
|
||||
auto child = make_ref<Node>(2);
|
||||
|
||||
// Create potential cycle
|
||||
parent->next = child; // Strong reference: parent → child
|
||||
child->parent = parent; // WeakRef: child ⇝ parent (breaks cycle)
|
||||
parent->next = child.copy(); // Strong reference: parent → child
|
||||
child->parent = parent.as_weak(); // WeakRef: child ⇝ parent (breaks cycle)
|
||||
|
||||
CHECK(parent->data == 1);
|
||||
CHECK(child->data == 2);
|
||||
@@ -286,7 +286,7 @@ TEST_CASE("Polymorphic Ref conversions") {
|
||||
CHECK(derived_ref->get_value() == 30); // 10 + 20
|
||||
|
||||
// Convert Ref<Derived> to Ref<Base>
|
||||
Ref<Base> base_ref = derived_ref;
|
||||
Ref<Base> base_ref = derived_ref.copy();
|
||||
CHECK(base_ref);
|
||||
CHECK(base_ref->get_value() == 30); // Virtual dispatch works
|
||||
CHECK(base_ref->base_value == 10);
|
||||
@@ -303,7 +303,7 @@ TEST_CASE("Polymorphic Ref conversions") {
|
||||
CHECK(base_ref->get_value() == 100);
|
||||
|
||||
// Assign derived to base
|
||||
base_ref = derived_ref;
|
||||
base_ref = derived_ref.copy();
|
||||
CHECK(base_ref->get_value() == 20); // 5 + 15
|
||||
CHECK(base_ref.get() == derived_ref.get());
|
||||
}
|
||||
@@ -338,7 +338,7 @@ TEST_CASE("Polymorphic Ref conversions") {
|
||||
CHECK(another_derived->get_value() == 24); // 6 * 4
|
||||
|
||||
// Convert to base
|
||||
Ref<Base> base_ref = another_derived;
|
||||
Ref<Base> base_ref = another_derived.copy();
|
||||
CHECK(base_ref->get_value() == 24); // Virtual dispatch
|
||||
CHECK(base_ref.get() == another_derived.get());
|
||||
}
|
||||
@@ -349,10 +349,10 @@ TEST_CASE("Polymorphic WeakRef conversions") {
|
||||
auto derived_ref = make_ref<Derived>(3, 7);
|
||||
|
||||
// Create WeakRef<Derived>
|
||||
WeakRef<Derived> weak_derived = derived_ref;
|
||||
WeakRef<Derived> weak_derived = derived_ref.as_weak();
|
||||
|
||||
// Convert to WeakRef<Base>
|
||||
WeakRef<Base> weak_base = weak_derived;
|
||||
WeakRef<Base> weak_base = weak_derived.copy();
|
||||
|
||||
// Both should lock to same object
|
||||
auto locked_derived = weak_derived.lock();
|
||||
@@ -368,11 +368,11 @@ TEST_CASE("Polymorphic WeakRef conversions") {
|
||||
auto derived_ref = make_ref<Derived>(4, 6);
|
||||
auto base_ref = make_ref<Base>(999);
|
||||
|
||||
WeakRef<Derived> weak_derived = derived_ref;
|
||||
WeakRef<Base> weak_base = base_ref;
|
||||
WeakRef<Derived> weak_derived = derived_ref.as_weak();
|
||||
WeakRef<Base> weak_base = base_ref.as_weak();
|
||||
|
||||
// Assign derived weak ref to base weak ref
|
||||
weak_base = weak_derived;
|
||||
weak_base = weak_derived.copy();
|
||||
|
||||
auto locked = weak_base.lock();
|
||||
CHECK(locked);
|
||||
@@ -384,7 +384,7 @@ TEST_CASE("Polymorphic WeakRef conversions") {
|
||||
auto derived_ref = make_ref<Derived>(2, 8);
|
||||
|
||||
// Create WeakRef<Base> directly from Ref<Derived>
|
||||
WeakRef<Base> weak_base = derived_ref;
|
||||
WeakRef<Base> weak_base = derived_ref.as_weak();
|
||||
|
||||
auto locked = weak_base.lock();
|
||||
CHECK(locked);
|
||||
@@ -394,7 +394,7 @@ TEST_CASE("Polymorphic WeakRef conversions") {
|
||||
|
||||
SUBCASE("WeakRef move operations") {
|
||||
auto derived_ref = make_ref<Derived>(1, 9);
|
||||
WeakRef<Derived> weak_derived = derived_ref;
|
||||
WeakRef<Derived> weak_derived = derived_ref.as_weak();
|
||||
|
||||
// Move construct
|
||||
WeakRef<Base> weak_base = std::move(weak_derived);
|
||||
@@ -414,7 +414,7 @@ TEST_CASE("Polymorphic edge cases") {
|
||||
CHECK(!empty_derived);
|
||||
|
||||
// Convert empty derived to base
|
||||
Ref<Base> empty_base = empty_derived;
|
||||
Ref<Base> empty_base = empty_derived.copy();
|
||||
CHECK(!empty_base);
|
||||
|
||||
// Move empty derived to base
|
||||
@@ -427,7 +427,7 @@ TEST_CASE("Polymorphic edge cases") {
|
||||
CHECK(!empty_weak_derived.lock());
|
||||
|
||||
// Convert empty weak derived to weak base
|
||||
WeakRef<Base> empty_weak_base = empty_weak_derived;
|
||||
WeakRef<Base> empty_weak_base = empty_weak_derived.copy();
|
||||
CHECK(!empty_weak_base.lock());
|
||||
}
|
||||
|
||||
@@ -435,7 +435,7 @@ TEST_CASE("Polymorphic edge cases") {
|
||||
auto derived_ref = make_ref<Derived>(5, 5);
|
||||
|
||||
// Ref<Derived> → WeakRef<Base>
|
||||
WeakRef<Base> weak_base_from_ref = derived_ref;
|
||||
WeakRef<Base> weak_base_from_ref = derived_ref.as_weak();
|
||||
|
||||
// WeakRef<Base> → Ref<Base> via lock
|
||||
auto base_ref_from_weak = weak_base_from_ref.lock();
|
||||
@@ -457,5 +457,5 @@ TEST_CASE("Self-referencing WeakRef pattern") {
|
||||
WeakRef<SelfReferencing> self_;
|
||||
};
|
||||
auto x = make_ref<SelfReferencing>();
|
||||
x->self_ = x;
|
||||
x->self_ = x.as_weak();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user