From 27c66f099b5bc0e320f77da82fb4c0a9e36f0265 Mon Sep 17 00:00:00 2001
From: Robert Sesek <rsesek@bluestatic.org>
Date: Sat, 8 Oct 2016 15:29:59 -0400
Subject: [PATCH] Fix ref::operator= for non-const lvalue binding to a
 temporary.

Implement operator= manually and reimplement the copy-ctor using it, rather than
vice versa. In addition, deleter_ gets changed to a pointer rather than
reference, so that a default ctor can be added.
---
 test.cc     | 18 ++++++++++++++++--
 zcpointer.h | 26 ++++++++++++++++----------
 2 files changed, 32 insertions(+), 12 deletions(-)

diff --git a/test.cc b/test.cc
index 92da993..4ea07e0 100644
--- a/test.cc
+++ b/test.cc
@@ -38,7 +38,10 @@ void TestReset() {
 template <typename T>
 void TestUnwrap() {
   zc::owned<T> t(new T());
-  T* unwrap = t.get();
+  //T* unwrap = t.get();
+
+  zc::ref<T> ref = t.get();
+  T* unwrap2 = ref;
 }
 
 void TestMove() {
@@ -52,6 +55,17 @@ void TestMove() {
   owned->DoThing();
 }
 
+void PtrHelper(zc::ref<C>* out) {
+  zc::owned<C> c(new C());
+  *out = c.get();
+}
+
+void TestPtr() {
+  zc::ref<C> ref;
+  PtrHelper(&ref);
+  ref->DoThing();
+}
+
 int main() {
-  TestMove();
+  TestPtr();
 }
diff --git a/zcpointer.h b/zcpointer.h
index ce4a821..bf86fb5 100644
--- a/zcpointer.h
+++ b/zcpointer.h
@@ -86,23 +86,29 @@ class owned : public std::unique_ptr<T, internal::OwnedPtrDeleter<T>> {
 template <typename T>
 class ref {
  public:
-  explicit ref(owned<T>& o) : ptr_(o.GetRawPointer()), deleter_(o.get_deleter()) {
-    deleter_.AddRef(this);
+  ref() : ptr_(nullptr), deleter_(nullptr), deleted_(true) {}
+
+  explicit ref(owned<T>& o) : ptr_(o.GetRawPointer()), deleter_(&o.get_deleter()) {
+    deleter_->AddRef(this);
   }
 
-  ref(const ref<T>& o) : ptr_(o.ptr_), deleter_(o.deleter_), deleted_(o.deleted_) {
-    if (!deleted_) {
-      deleter_.AddRef(this);
-    }
+  ref(const ref<T>& o) {
+    *this = o;
   }
 
-  ref<T>& operator=(ref<T> o) {
-    return ref(o);
+  ref<T>& operator=(const ref<T>& o) {
+    ptr_ = o.ptr_;
+    deleter_ = o.deleter_;
+    deleted_ = o.deleted_;
+    if (!deleted_) {
+      deleter_->AddRef(this);
+    }
+    return *this;
   }
 
   ~ref() {
     MarkDeleted();
-    deleter_.RemoveRef(this);
+    deleter_->RemoveRef(this);
   }
 
   T* operator->() const {
@@ -125,7 +131,7 @@ class ref {
   }
 
   T* ptr_;
-  internal::OwnedPtrDeleter<T>& deleter_;
+  internal::OwnedPtrDeleter<T>* deleter_;
   bool deleted_ = false;
 };
 
-- 
2.43.5