diff options
author | Murray Cumming <murrayc@murrayc.com> | 2016-04-28 11:03:26 +0200 |
---|---|---|
committer | Murray Cumming <murrayc@murrayc.com> | 2016-05-02 10:19:49 +0200 |
commit | 57a20ea1f4b64c82e2c6c4711619393415e88af1 (patch) | |
tree | 839f51e2e2983025152861ad350d34376f24ed9f | |
parent | eb53dd6bc9aa1ed6d44cb2b8ebba3093e7e5e4bb (diff) | |
download | sigc++-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.am | 1 | ||||
-rw-r--r-- | sigc++/weak_raw_ptr.h | 109 | ||||
-rw-r--r-- | tests/.gitignore | 1 | ||||
-rw-r--r-- | tests/CMakeLists.txt | 3 | ||||
-rw-r--r-- | tests/Makefile.am | 4 | ||||
-rw-r--r-- | 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, ¬ify_object_invalidated); + } + + inline weak_raw_ptr(const weak_raw_ptr& src) noexcept + : p_(src.p_) + { + p_->add_destroy_notify_callback(this, ¬ify_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, ¬ify_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; +} |