diff --git a/src/rcu.h b/src/rcu.h --- a/src/rcu.h +++ b/src/rcu.h @@ -139,6 +139,22 @@ 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(); + } + } + + template RCUPtr &operator=(const RCUPtr &rhs) { + RCUPtr tmp(rhs); + std::swap(ptr, tmp.ptr); + return *this; + } + /** * Move semantic. */ 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,55 @@ BOOST_CHECK(isDestroyed); } +BOOST_AUTO_TEST_CASE(rcu_converting_constructor) { + bool isDestroyed = false; + + auto rcuNonConst = + RCUPtr::make([&] { isDestroyed = true; }); + BOOST_CHECK_EQUAL(rcuNonConst->getRefCount(), 0); + + RCUPtr rcuConst(rcuNonConst); + BOOST_CHECK_EQUAL(rcuConst->getRefCount(), 1); + BOOST_CHECK_EQUAL(rcuNonConst->getRefCount(), 1); + + rcuNonConst = RCUPtr(); + + // 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_CASE(rcu_converting_assignment) { + bool isDestroyed = false; + auto rcuConst = RCUPtr(); + + { + 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()