[RefCounted] allow RefCounted<> to work for const types

pull/35188/head
Mark D. Roth 1 year ago
parent f9e56a9467
commit 667de345f7
  1. 48
      src/core/lib/gprpp/ref_counted.h
  2. 11
      test/core/gprpp/ref_counted_test.cc

@ -219,7 +219,7 @@ class NonPolymorphicRefCount {
// Default behavior: Delete the object. // Default behavior: Delete the object.
struct UnrefDelete { struct UnrefDelete {
template <typename T> template <typename T>
void operator()(T* p) { void operator()(T* p) const {
delete p; delete p;
} }
}; };
@ -231,7 +231,7 @@ struct UnrefDelete {
// later by identifying entries for which RefIfNonZero() returns null. // later by identifying entries for which RefIfNonZero() returns null.
struct UnrefNoDelete { struct UnrefNoDelete {
template <typename T> template <typename T>
void operator()(T* /*p*/) {} void operator()(T* /*p*/) const {}
}; };
// Call the object's dtor but do not delete it. This is useful for cases // Call the object's dtor but do not delete it. This is useful for cases
@ -239,7 +239,7 @@ struct UnrefNoDelete {
// arena). // arena).
struct UnrefCallDtor { struct UnrefCallDtor {
template <typename T> template <typename T>
void operator()(T* p) { void operator()(T* p) const {
p->~T(); p->~T();
} }
}; };
@ -279,32 +279,44 @@ class RefCounted : public Impl {
// Note: Depending on the Impl used, this dtor can be implicitly virtual. // Note: Depending on the Impl used, this dtor can be implicitly virtual.
~RefCounted() = default; ~RefCounted() = default;
// Ref() for mutable types.
GRPC_MUST_USE_RESULT RefCountedPtr<Child> Ref() { GRPC_MUST_USE_RESULT RefCountedPtr<Child> Ref() {
IncrementRefCount(); IncrementRefCount();
return RefCountedPtr<Child>(static_cast<Child*>(this)); return RefCountedPtr<Child>(static_cast<Child*>(this));
} }
GRPC_MUST_USE_RESULT RefCountedPtr<Child> Ref(const DebugLocation& location, GRPC_MUST_USE_RESULT RefCountedPtr<Child> Ref(const DebugLocation& location,
const char* reason) { const char* reason) {
IncrementRefCount(location, reason); IncrementRefCount(location, reason);
return RefCountedPtr<Child>(static_cast<Child*>(this)); return RefCountedPtr<Child>(static_cast<Child*>(this));
} }
// Ref() for const types.
GRPC_MUST_USE_RESULT RefCountedPtr<const Child> Ref() const {
IncrementRefCount();
return RefCountedPtr<const Child>(static_cast<const Child*>(this));
}
GRPC_MUST_USE_RESULT RefCountedPtr<const Child> Ref(
const DebugLocation& location, const char* reason) const {
IncrementRefCount(location, reason);
return RefCountedPtr<const Child>(static_cast<const Child*>(this));
}
// TODO(roth): Once all of our code is converted to C++ and can use // TODO(roth): Once all of our code is converted to C++ and can use
// RefCountedPtr<> instead of manual ref-counting, make this method // RefCountedPtr<> instead of manual ref-counting, make this method
// private, since it will only be used by RefCountedPtr<>, which is a // private, since it will only be used by RefCountedPtr<>, which is a
// friend of this class. // friend of this class.
void Unref() { void Unref() const {
if (GPR_UNLIKELY(refs_.Unref())) { if (GPR_UNLIKELY(refs_.Unref())) {
unref_behavior_(static_cast<Child*>(this)); unref_behavior_(static_cast<const Child*>(this));
} }
} }
void Unref(const DebugLocation& location, const char* reason) { void Unref(const DebugLocation& location, const char* reason) const {
if (GPR_UNLIKELY(refs_.Unref(location, reason))) { if (GPR_UNLIKELY(refs_.Unref(location, reason))) {
unref_behavior_(static_cast<Child*>(this)); unref_behavior_(static_cast<const Child*>(this));
} }
} }
// RefIfNonZero() for mutable types.
GRPC_MUST_USE_RESULT RefCountedPtr<Child> RefIfNonZero() { GRPC_MUST_USE_RESULT RefCountedPtr<Child> RefIfNonZero() {
return RefCountedPtr<Child>(refs_.RefIfNonZero() ? static_cast<Child*>(this) return RefCountedPtr<Child>(refs_.RefIfNonZero() ? static_cast<Child*>(this)
: nullptr); : nullptr);
@ -316,6 +328,19 @@ class RefCounted : public Impl {
: nullptr); : nullptr);
} }
// RefIfNonZero() for const types.
GRPC_MUST_USE_RESULT RefCountedPtr<const Child> RefIfNonZero() const {
return RefCountedPtr<const Child>(refs_.RefIfNonZero()
? static_cast<const Child*>(this)
: nullptr);
}
GRPC_MUST_USE_RESULT RefCountedPtr<const Child> RefIfNonZero(
const DebugLocation& location, const char* reason) const {
return RefCountedPtr<const Child>(refs_.RefIfNonZero(location, reason)
? static_cast<const Child*>(this)
: nullptr);
}
// Not copyable nor movable. // Not copyable nor movable.
RefCounted(const RefCounted&) = delete; RefCounted(const RefCounted&) = delete;
RefCounted& operator=(const RefCounted&) = delete; RefCounted& operator=(const RefCounted&) = delete;
@ -336,12 +361,13 @@ class RefCounted : public Impl {
template <typename T> template <typename T>
friend class RefCountedPtr; friend class RefCountedPtr;
void IncrementRefCount() { refs_.Ref(); } void IncrementRefCount() const { refs_.Ref(); }
void IncrementRefCount(const DebugLocation& location, const char* reason) { void IncrementRefCount(const DebugLocation& location, const char* reason)
const {
refs_.Ref(location, reason); refs_.Ref(location, reason);
} }
RefCount refs_; mutable RefCount refs_;
GPR_NO_UNIQUE_ADDRESS UnrefBehavior unref_behavior_; GPR_NO_UNIQUE_ADDRESS UnrefBehavior unref_behavior_;
}; };

@ -53,6 +53,17 @@ TEST(RefCounted, ExtraRef) {
foo->Unref(); foo->Unref();
} }
TEST(RefCounted, Const) {
const Foo* foo = new Foo();
RefCountedPtr<const Foo> foop = foo->Ref();
foop.release();
foop = foo->RefIfNonZero();
foop.release();
foo->Unref();
foo->Unref();
foo->Unref();
}
class Value : public RefCounted<Value, PolymorphicRefCount, UnrefNoDelete> { class Value : public RefCounted<Value, PolymorphicRefCount, UnrefNoDelete> {
public: public:
Value(int value, std::set<std::unique_ptr<Value>>* registry) : value_(value) { Value(int value, std::set<std::unique_ptr<Value>>* registry) : value_(value) {

Loading…
Cancel
Save