[libsigcplusplus] Added sigc::internal::weak_raw_ptr<>.



commit 57a20ea1f4b64c82e2c6c4711619393415e88af1
Author: Murray Cumming <murrayc murrayc com>
Date:   Thu Apr 28 11:03:26 2016 +0200

    Added sigc::internal::weak_raw_ptr<>.
    
    As a simpler way to null a pointer to an object when that object
    is deleted.

 sigc++/filelist.am         |    1 +
 sigc++/weak_raw_ptr.h      |  109 ++++++++++++++++++++++++++++++++++++++++++++
 tests/.gitignore           |    1 +
 tests/CMakeLists.txt       |    3 +-
 tests/Makefile.am          |    4 +-
 tests/test_weak_raw_ptr.cc |   73 +++++++++++++++++++++++++++++
 6 files changed, 189 insertions(+), 2 deletions(-)
---
diff --git a/sigc++/filelist.am b/sigc++/filelist.am
index a65f8b9..7ee3cc0 100644
--- a/sigc++/filelist.am
+++ b/sigc++/filelist.am
@@ -35,6 +35,7 @@ sigc_public_h =                               \
        tuple-utils/tuple_transform_each.h \
        type_traits.h                   \
        visit_each.h                    \
+       weak_raw_ptr.h                  \
        adaptors/adapts.h               \
        adaptors/adaptor_base.h \
        adaptors/adaptors.h             \
diff --git a/sigc++/weak_raw_ptr.h b/sigc++/weak_raw_ptr.h
new file mode 100644
index 0000000..c2e3fcb
--- /dev/null
+++ b/sigc++/weak_raw_ptr.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2016, The libsigc++ Development Team
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef SIGC_WEAK_RAW_PTR_HPP
+#define SIGC_WEAK_RAW_PTR_HPP
+#include <sigc++/trackable.h> //Just for notifiable.
+
+namespace sigc
+{
+
+struct notifiable;
+
+namespace internal
+{
+
+/** T must derive from sigc::trackable.
+ */
+template <typename T>
+struct weak_raw_ptr : public sigc::notifiable
+{
+  inline weak_raw_ptr()
+  : p_(nullptr)
+  {}
+  
+  inline weak_raw_ptr(T* p) noexcept
+  : p_(p)
+  {
+    if(!p)
+      return;
+      
+    p->add_destroy_notify_callback(this, &notify_object_invalidated);
+  }
+  
+  inline weak_raw_ptr(const weak_raw_ptr& src) noexcept
+  : p_(src.p_)
+  {
+    p_->add_destroy_notify_callback(this, &notify_object_invalidated);
+  }
+  
+  inline weak_raw_ptr& operator=(const weak_raw_ptr& src) noexcept
+  {
+    if(p_) {
+      p_->remove_destroy_notify_callback(this);
+    }
+
+    p_ = src.p_;
+    p_->add_destroy_notify_callback(this, &notify_object_invalidated);
+
+    return *this;
+  }
+
+  //TODO:
+  weak_raw_ptr(weak_raw_ptr&& src) = delete;
+  weak_raw_ptr& operator=(weak_raw_ptr&& src) = delete;
+  
+  inline ~weak_raw_ptr() noexcept
+  {
+    if (p_) {
+      p_->remove_destroy_notify_callback(this);
+    }
+  }
+  
+  inline explicit operator bool() const noexcept
+  {
+    return p_ != nullptr;
+  }
+
+  inline T* operator->() const noexcept
+  {
+    return p_;
+  }
+
+private:
+  /** Callback that is executed when the objet is destroyed.
+   * @param data The object notified (@p this).
+   */
+  static void notify_object_invalidated(notifiable* data)
+  {
+    weak_raw_ptr* self = static_cast<weak_raw_ptr*>(data);
+    if(!self)
+      return;
+
+    self->p_ = nullptr;
+  }
+  
+  T* p_;
+};
+
+} /* namespace internal */
+
+} /* namespace sigc */
+
+#endif /* SIGC_WEAK_RAW_PTR_HPP */
diff --git a/tests/.gitignore b/tests/.gitignore
index f3b439f..ca60f86 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -40,4 +40,5 @@
 /test_tuple_transform_each
 /test_visit_each
 /test_visit_each_trackable
+/test_weak_raw_ptr
 /benchmark
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 65f1dd1..ab089eb 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -53,7 +53,8 @@ set (TEST_SOURCE_FILES
   test_tuple_start.cc
   test_tuple_transform_each.cc
   test_visit_each.cc
-  test_visit_each_trackable.cc)
+  test_visit_each_trackable.cc
+  test_weak_raw_ptr.cc)
 
 function (add_sigcpp_test TEST_SOURCE_FILE)
        get_filename_component (test_name ${TEST_SOURCE_FILE} NAME_WE)
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 296096c..114789f 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -60,7 +60,8 @@ check_PROGRAMS = \
   test_tuple_start \
   test_tuple_transform_each \
   test_visit_each \
-  test_visit_each_trackable
+  test_visit_each_trackable \
+  test_weak_raw_ptr
 
 TESTS = $(check_PROGRAMS)
 
@@ -103,6 +104,7 @@ test_tuple_start_SOURCES     = test_tuple_start.cc $(sigc_test_util)
 test_tuple_transform_each_SOURCES = test_tuple_transform_each.cc $(sigc_test_util)
 test_visit_each_SOURCES      = test_visit_each.cc $(sigc_test_util)
 test_visit_each_trackable_SOURCES = test_visit_each_trackable.cc $(sigc_test_util)
+test_weak_raw_ptr_SOURCES = test_weak_raw_ptr.cc $(sigc_test_util)
 
 if SIGC_BUILD_BENCHMARK
 check_PROGRAMS += benchmark
diff --git a/tests/test_weak_raw_ptr.cc b/tests/test_weak_raw_ptr.cc
new file mode 100644
index 0000000..82a159a
--- /dev/null
+++ b/tests/test_weak_raw_ptr.cc
@@ -0,0 +1,73 @@
+/* Copyright 2016, The libsigc++ Development Team
+ *  Assigned to public domain.  Use as you wish without restriction.
+ */
+
+#include "testutilities.h"
+#include <sigc++/weak_raw_ptr.h>
+#include <cassert>
+
+namespace
+{
+
+TestUtilities* util = nullptr;
+std::ostringstream result_stream;
+
+class A : public sigc::trackable
+{
+public:
+  void something()
+  {
+    result_stream << "method called";
+  }
+};
+
+} // end anonymous namespace
+
+void test_weak_ptr_becomes_null()
+{
+  const auto a = new A();
+  sigc::internal::weak_raw_ptr<A> raw_ptr(a);
+  assert(raw_ptr);
+
+  //Call something on A, via the weak_raw_ptr<>,
+  //just to make sure that it doesn't get optimised away:
+  raw_ptr->something();
+  util->check_result(result_stream, "method called");
+
+  delete a;
+
+  //Deleting the A should have made the weak_raw_ptr<A> become invalid.
+  assert(!raw_ptr);
+}
+
+void test_weak_ptr_disconnects_self()
+{
+  const auto a = new A();
+  {
+    sigc::internal::weak_raw_ptr<A> raw_ptr(a);
+
+    //Call something on A, via the weak_raw_ptr<>,
+    //just to make sure that it doesn't get optimised away:
+    raw_ptr->something();
+    util->check_result(result_stream, "method called");
+  }
+
+  //If the weak_raw_ptr has not asked A to stop notifying it,
+  //then we would expect some undefined behaviour here,
+  //when a tries to notify the now-destroyed weak_raw_ptr.
+  delete a;
+}
+
+int
+main(int argc, char* argv[])
+{
+  util = TestUtilities::get_instance();
+
+  if (!util->check_command_args(argc, argv))
+    return util->get_result_and_delete_instance() ? EXIT_SUCCESS : EXIT_FAILURE;
+
+  test_weak_ptr_becomes_null();
+  test_weak_ptr_disconnects_self();
+
+  return util->get_result_and_delete_instance() ? EXIT_SUCCESS : EXIT_FAILURE;
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]