summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMurray Cumming <murrayc@murrayc.com>2016-04-28 11:03:26 +0200
committerMurray Cumming <murrayc@murrayc.com>2016-05-02 10:19:49 +0200
commit57a20ea1f4b64c82e2c6c4711619393415e88af1 (patch)
tree839f51e2e2983025152861ad350d34376f24ed9f
parenteb53dd6bc9aa1ed6d44cb2b8ebba3093e7e5e4bb (diff)
downloadsigc++-57a20ea1f4b64c82e2c6c4711619393415e88af1.tar.gz
Added sigc::internal::weak_raw_ptr<>.
As a simpler way to null a pointer to an object when that object is deleted.
-rw-r--r--sigc++/filelist.am1
-rw-r--r--sigc++/weak_raw_ptr.h109
-rw-r--r--tests/.gitignore1
-rw-r--r--tests/CMakeLists.txt3
-rw-r--r--tests/Makefile.am4
-rw-r--r--tests/test_weak_raw_ptr.cc73
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;
+}