diff --git a/src/rcu.h b/src/rcu.h --- a/src/rcu.h +++ b/src/rcu.h @@ -148,6 +148,16 @@ return *this; } + /** + * Implicit converting constructor from RCUPtr to RCUPtr, where U * is + * implicitely convertible to T *. + */ + template RCUPtr(const RCUPtr &src) : ptr(src.get()) { + if (ptr != nullptr) { + ptr->incrementRefCount(); + } + } + /** * Get allows to access the undelying pointer. RCUPtr keeps ownership. */ diff --git a/src/test/rcu_tests.cpp b/src/test/rcu_tests.cpp --- a/src/test/rcu_tests.cpp +++ b/src/test/rcu_tests.cpp @@ -421,4 +421,31 @@ BOOST_CHECK(isDestroyed); } +BOOST_AUTO_TEST_CASE(rcu_conversion) { + bool isDestroyed = false; + auto rcuConst = RCUPtr(); + + { + // Copy construct after an implicit conversion + auto rcuNonConst = + RCUPtr::make([&] { isDestroyed = true; }); + BOOST_CHECK_EQUAL(rcuNonConst->getRefCount(), 0); + + rcuConst = rcuNonConst; + BOOST_CHECK_EQUAL(rcuConst->getRefCount(), 1); + BOOST_CHECK_EQUAL(rcuNonConst->getRefCount(), 1); + } + + // We still have a copy + BOOST_CHECK(!isDestroyed); + RCULock::synchronize(); + BOOST_CHECK(!isDestroyed); + + // Destroy the copy + rcuConst = RCUPtr(); + BOOST_CHECK(!isDestroyed); + RCULock::synchronize(); + BOOST_CHECK(isDestroyed); +} + BOOST_AUTO_TEST_SUITE_END()