Add member<T> for non-pointer member varibables and stack locals.
authorRobert Sesek <rsesek@bluestatic.org>
Mon, 10 Oct 2016 18:56:42 +0000 (14:56 -0400)
committerRobert Sesek <rsesek@bluestatic.org>
Tue, 11 Oct 2016 22:53:02 +0000 (18:53 -0400)
Makefile
README.md
test.cc
test_helpers.cc [new file with mode: 0644]
test_helpers.h [new file with mode: 0644]
zcpointer.h

index 2245bf2..5b8d2af 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -5,9 +5,9 @@ ifeq ($(OPTIMIZED),1)
        CXXFLAGS += -O2
 endif
 
-FILES := test.cc zcpointer.cc
+FILES := test.cc test_helpers.cc zcpointer.cc
 
-DEPS := $(FILES) zcpointer.h Makefile
+DEPS := $(FILES) zcpointer.h test_helpers.h Makefile
 
 all: test-zc test-tr
 
index 571a611..68cc5e2 100644 (file)
--- a/README.md
+++ b/README.md
@@ -5,12 +5,15 @@ The zcpointer library is a specialization of
 references. The goal is to allow C++ developers to write programs without _ever_ having a pointer
 that is not automatically managed by a smart scoper.
 
-The library provides two types to do this:
+The library provides three types to do this:
 
 - `zc::owned<T>` provides an identical interface to `std::unique_ptr<T>`, but which can track outstanding
   weak references.
 - `zc::ref<T>` is the return value of `zc::owned<T>::get()`. It stands for a `T*` but is used to
   ensure use-after-free does not occur.
+- `zc::member<T>` is used to wrap member or local variables that should be constructed in-place, but
+  which may have pointers-to vended out to other objects. This overloads `zc::member<T>::operator&`
+  to return a `zc::ref<T>` when taking the address.
 
 To achieve zero-cost, the zcpointer library can be compiled with or without the
 `ZCPOINTER_TRACK_REFS` option. When disabled, `zc::owned` is just a type alias for `std::unique_ptr`
diff --git a/test.cc b/test.cc
index e8cbdf2..c519322 100644 (file)
--- a/test.cc
+++ b/test.cc
 #include <stdexcept>
 #include <vector>
 
+#include "test_helpers.h"
 #include "zcpointer.h"
 
-class C {
- public:
-  ~C() {}
-
-  void DoThing() {}
-};
-
 class TestFailure : public std::logic_error {
  public:
   using std::logic_error::logic_error;
@@ -169,6 +163,34 @@ void TestVector() {
   EXPECT_UAF(ref->DoThing());
 }
 
+void TestStack() {
+  zc::ref<C> rc;
+  {
+    zc::member<C> c;
+    rc = &c;
+    EXPECT(rc == &c);
+    c->DoThing();
+  }
+  EXPECT_UAF(rc->DoThing());
+}
+
+void TestMember() {
+  zc::ref<C> ref;
+  zc::ref<std::vector<C>> vec_ref;
+  {
+    X x("hello world");
+    ref = x.c();
+    vec_ref = x.vec_c();
+
+    vec_ref->push_back(C());
+    vec_ref->push_back(C());
+
+    vec_ref->at(1).DoThing();
+  }
+  EXPECT_UAF(ref->DoThing());
+  EXPECT_UAF(vec_ref->at(1).DoThing());
+}
+
 #define TEST_FUNC(fn) { #fn , Test##fn }
 
 int main() {
@@ -182,6 +204,8 @@ int main() {
     TEST_FUNC(Equality),
     TEST_FUNC(Nulls),
     TEST_FUNC(Vector),
+    TEST_FUNC(Stack),
+    TEST_FUNC(Member),
   };
 
   bool passed = true;
diff --git a/test_helpers.cc b/test_helpers.cc
new file mode 100644 (file)
index 0000000..45cba9b
--- /dev/null
@@ -0,0 +1,34 @@
+// Copyright 2016 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "test_helpers.h"
+
+C::C() {}
+
+C::~C() {}
+
+void C::DoThing() {}
+
+X::X(const char* v) : foo_(v) {}
+
+X::~X() {}
+
+size_t X::GetCount() const {
+  return vec_c_->size();
+}
+
+std::string X::DoString() {
+  vec_c_->push_back(C());
+  return foo_;
+}
diff --git a/test_helpers.h b/test_helpers.h
new file mode 100644 (file)
index 0000000..d4062db
--- /dev/null
@@ -0,0 +1,49 @@
+// Copyright 2016 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ZCPOINTER_TEST_HELPERS_H_
+#define ZCPOINTER_TEST_HELPERS_H_
+
+#include <string>
+#include <vector>
+
+#include "zcpointer.h"
+
+class C {
+ public:
+  C();
+  ~C();
+  void DoThing();
+};
+
+class X {
+ public:
+  X(const char* v);
+  ~X();
+
+  zc::ref<C> c() { return &c_; }
+
+  zc::ref<std::vector<C>> vec_c() { return &vec_c_; }
+
+  size_t GetCount() const;
+
+  std::string DoString();
+
+ private:
+  std::string foo_;
+  zc::member<C> c_;
+  zc::member<std::vector<C>> vec_c_;
+};
+
+#endif  // ZCPOINTER_TEST_HELPERS_H_
index b9bb511..9af37d6 100644 (file)
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#ifndef ZCPOINTER_ZCPOINTER_H_
+#define ZCPOINTER_ZCPOINTER_H_
+
 #include <limits>
 #include <memory>
 #include <forward_list>
 #include <stdexcept>
+#include <utility>
 
 namespace zc {
 
@@ -166,6 +170,30 @@ class ref {
   owned<T>* ptr_;
 };
 
+template <typename T>
+class member {
+ public:
+  template <typename... Args>
+  explicit member(Args&&... args)
+    : t_(new T(std::forward<Args>(args)...)) {
+  }
+
+  ref<T> operator&() {
+    return t_.get();
+  }
+
+  T* operator->() {
+    return t_.operator->();
+  }
+
+  const T* operator->() const {
+    return t_.operator->();
+  }
+
+ private:
+  owned<T> t_;
+};
+
 #else
 
 template <typename T>
@@ -174,6 +202,22 @@ using owned = std::unique_ptr<T>;
 template <typename T>
 using ref = T*;
 
+template <typename T>
+class member : public T {
+ public:
+  using T::T;
+
+  T* operator->() {
+    return this;
+  }
+
+  const T* operator->() const {
+    return this;
+  }
+};
+
 #endif
 
 }  // namespace zc
+
+#endif  // ZCPOINTER_ZCPOINTER_H_