From 2c9662613c2d99dc2e5857f2c58bca526a237517 Mon Sep 17 00:00:00 2001 From: Robert Sesek Date: Sat, 8 Oct 2016 20:54:21 -0400 Subject: [PATCH] ref::ref() now initializes to nullptr. Improve boolean comparisons for ref. Also add internal::OwnedPtrDeleter::operator= to suport std::move of owned. --- test.cc | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ zcpointer.h | 41 +++++++++++++++++++++++++++++++++-------- 2 files changed, 84 insertions(+), 8 deletions(-) diff --git a/test.cc b/test.cc index e7171d3..95f749d 100644 --- a/test.cc +++ b/test.cc @@ -71,6 +71,55 @@ void TestPtr() { EXPECT_UAF(ref->DoThing()); } +void TestEquality() { + zc::owned a(new C()); + zc::owned b(new C()); + + EXPECT(a == a); + EXPECT(b == b); + EXPECT(a != b); + + zc::ref ra = a.get(); + zc::ref rb = b.get(); + + EXPECT(ra == ra); + EXPECT(ra == a.get()); + EXPECT(rb == rb); + EXPECT(rb == b.get()); + + EXPECT(rb != ra); + + zc::ref r = a.get(); + EXPECT(r == ra); + EXPECT(r == a.get()); + + zc::owned c; + zc::owned c2; + zc::ref rc = nullptr; + + EXPECT(rc == c.get()); + EXPECT(c == nullptr); + EXPECT(rc == nullptr); + EXPECT(a != c); + EXPECT(c == c2); +} + +void TestNulls() { + zc::owned l; + zc::owned r; + + zc::ref rl = l.get(); + zc::ref rr = r.get(); + + r = std::move(l); + rl = rr; + + EXPECT(l == nullptr); + EXPECT(r == nullptr); + EXPECT(rl == nullptr); + EXPECT(rr == nullptr); +} + #define TEST_FUNC(fn) { #fn , Test##fn } int main() { @@ -81,6 +130,8 @@ int main() { TEST_FUNC(Reset), TEST_FUNC(Move), TEST_FUNC(Ptr), + TEST_FUNC(Equality), + TEST_FUNC(Nulls), }; bool passed = true; diff --git a/zcpointer.h b/zcpointer.h index 10251c1..b9bb511 100644 --- a/zcpointer.h +++ b/zcpointer.h @@ -39,6 +39,10 @@ class OwnedPtrDeleter { OwnedPtrDeleter(OwnedPtrDeleter&& other) : refs_(std::move(other.refs_)) { } + void operator=(const OwnedPtrDeleter& o) { + refs_ = o.refs_; + } + void operator()(T* t) const { for (auto& ref : refs_) { ref->MarkDeleted(); @@ -86,29 +90,34 @@ class owned : public std::unique_ptr> { template class ref { public: - ref() : ptr_(DeletedSentinel()) {} + ref() : ptr_(nullptr) {} + + ref(std::nullptr_t) : ref() {} - explicit ref(owned& o) : ptr_(&o) { - ptr_->get_deleter().AddRef(this); + explicit ref(owned& o) : ptr_(nullptr) { + if (o != nullptr) { + ptr_ = &o; + ptr_->get_deleter().AddRef(this); + } } - ref(const ref& o) { - *this = o; + ref(const ref& r) { + *this = r; } ref& operator=(const ref& o) { ptr_ = o.ptr_; - if (!IsDeleted()) { + if (ptr_ != nullptr && !IsDeleted()) { ptr_->get_deleter().AddRef(this); } return *this; } ~ref() { - if (!IsDeleted()) { + if (ptr_ != nullptr && !IsDeleted()) { ptr_->get_deleter().RemoveRef(this); - MarkDeleted(); } + MarkDeleted(); } T* operator->() const { @@ -116,6 +125,22 @@ class ref { return ptr_->operator->(); } + bool operator==(const ref& r) const { + if (ptr_ == nullptr) { + return r.ptr_ == nullptr; + } else { + return ptr_ == r.ptr_ && *ptr_ == *r.ptr_; + } + } + + bool operator==(std::nullptr_t) const { + return ptr_ == nullptr; + } + + bool operator!=(const ref& r) const { + return !(*this == r); + } + protected: friend class internal::OwnedPtrDeleter; -- 2.22.5