Skip to content

Commit 57a20ea

Browse files
committed
Added sigc::internal::weak_raw_ptr<>.
As a simpler way to null a pointer to an object when that object is deleted.
1 parent eb53dd6 commit 57a20ea

File tree

6 files changed

+189
-2
lines changed

6 files changed

+189
-2
lines changed

sigc++/filelist.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ sigc_public_h = \
3535
tuple-utils/tuple_transform_each.h \
3636
type_traits.h \
3737
visit_each.h \
38+
weak_raw_ptr.h \
3839
adaptors/adapts.h \
3940
adaptors/adaptor_base.h \
4041
adaptors/adaptors.h \

sigc++/weak_raw_ptr.h

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/*
2+
* Copyright 2016, The libsigc++ Development Team
3+
*
4+
* This library is free software; you can redistribute it and/or
5+
* modify it under the terms of the GNU Lesser General Public
6+
* License as published by the Free Software Foundation; either
7+
* version 2.1 of the License, or (at your option) any later version.
8+
*
9+
* This library is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12+
* Lesser General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU Lesser General Public
15+
* License along with this library; if not, write to the Free Software
16+
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17+
*
18+
*/
19+
20+
#ifndef SIGC_WEAK_RAW_PTR_HPP
21+
#define SIGC_WEAK_RAW_PTR_HPP
22+
#include <sigc++/trackable.h> //Just for notifiable.
23+
24+
namespace sigc
25+
{
26+
27+
struct notifiable;
28+
29+
namespace internal
30+
{
31+
32+
/** T must derive from sigc::trackable.
33+
*/
34+
template <typename T>
35+
struct weak_raw_ptr : public sigc::notifiable
36+
{
37+
inline weak_raw_ptr()
38+
: p_(nullptr)
39+
{}
40+
41+
inline weak_raw_ptr(T* p) noexcept
42+
: p_(p)
43+
{
44+
if(!p)
45+
return;
46+
47+
p->add_destroy_notify_callback(this, &notify_object_invalidated);
48+
}
49+
50+
inline weak_raw_ptr(const weak_raw_ptr& src) noexcept
51+
: p_(src.p_)
52+
{
53+
p_->add_destroy_notify_callback(this, &notify_object_invalidated);
54+
}
55+
56+
inline weak_raw_ptr& operator=(const weak_raw_ptr& src) noexcept
57+
{
58+
if(p_) {
59+
p_->remove_destroy_notify_callback(this);
60+
}
61+
62+
p_ = src.p_;
63+
p_->add_destroy_notify_callback(this, &notify_object_invalidated);
64+
65+
return *this;
66+
}
67+
68+
//TODO:
69+
weak_raw_ptr(weak_raw_ptr&& src) = delete;
70+
weak_raw_ptr& operator=(weak_raw_ptr&& src) = delete;
71+
72+
inline ~weak_raw_ptr() noexcept
73+
{
74+
if (p_) {
75+
p_->remove_destroy_notify_callback(this);
76+
}
77+
}
78+
79+
inline explicit operator bool() const noexcept
80+
{
81+
return p_ != nullptr;
82+
}
83+
84+
inline T* operator->() const noexcept
85+
{
86+
return p_;
87+
}
88+
89+
private:
90+
/** Callback that is executed when the objet is destroyed.
91+
* @param data The object notified (@p this).
92+
*/
93+
static void notify_object_invalidated(notifiable* data)
94+
{
95+
weak_raw_ptr* self = static_cast<weak_raw_ptr*>(data);
96+
if(!self)
97+
return;
98+
99+
self->p_ = nullptr;
100+
}
101+
102+
T* p_;
103+
};
104+
105+
} /* namespace internal */
106+
107+
} /* namespace sigc */
108+
109+
#endif /* SIGC_WEAK_RAW_PTR_HPP */

tests/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,5 @@
4040
/test_tuple_transform_each
4141
/test_visit_each
4242
/test_visit_each_trackable
43+
/test_weak_raw_ptr
4344
/benchmark

tests/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ set (TEST_SOURCE_FILES
5353
test_tuple_start.cc
5454
test_tuple_transform_each.cc
5555
test_visit_each.cc
56-
test_visit_each_trackable.cc)
56+
test_visit_each_trackable.cc
57+
test_weak_raw_ptr.cc)
5758

5859
function (add_sigcpp_test TEST_SOURCE_FILE)
5960
get_filename_component (test_name ${TEST_SOURCE_FILE} NAME_WE)

tests/Makefile.am

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ check_PROGRAMS = \
6060
test_tuple_start \
6161
test_tuple_transform_each \
6262
test_visit_each \
63-
test_visit_each_trackable
63+
test_visit_each_trackable \
64+
test_weak_raw_ptr
6465

6566
TESTS = $(check_PROGRAMS)
6667

@@ -103,6 +104,7 @@ test_tuple_start_SOURCES = test_tuple_start.cc $(sigc_test_util)
103104
test_tuple_transform_each_SOURCES = test_tuple_transform_each.cc $(sigc_test_util)
104105
test_visit_each_SOURCES = test_visit_each.cc $(sigc_test_util)
105106
test_visit_each_trackable_SOURCES = test_visit_each_trackable.cc $(sigc_test_util)
107+
test_weak_raw_ptr_SOURCES = test_weak_raw_ptr.cc $(sigc_test_util)
106108

107109
if SIGC_BUILD_BENCHMARK
108110
check_PROGRAMS += benchmark

tests/test_weak_raw_ptr.cc

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/* Copyright 2016, The libsigc++ Development Team
2+
* Assigned to public domain. Use as you wish without restriction.
3+
*/
4+
5+
#include "testutilities.h"
6+
#include <sigc++/weak_raw_ptr.h>
7+
#include <cassert>
8+
9+
namespace
10+
{
11+
12+
TestUtilities* util = nullptr;
13+
std::ostringstream result_stream;
14+
15+
class A : public sigc::trackable
16+
{
17+
public:
18+
void something()
19+
{
20+
result_stream << "method called";
21+
}
22+
};
23+
24+
} // end anonymous namespace
25+
26+
void test_weak_ptr_becomes_null()
27+
{
28+
const auto a = new A();
29+
sigc::internal::weak_raw_ptr<A> raw_ptr(a);
30+
assert(raw_ptr);
31+
32+
//Call something on A, via the weak_raw_ptr<>,
33+
//just to make sure that it doesn't get optimised away:
34+
raw_ptr->something();
35+
util->check_result(result_stream, "method called");
36+
37+
delete a;
38+
39+
//Deleting the A should have made the weak_raw_ptr<A> become invalid.
40+
assert(!raw_ptr);
41+
}
42+
43+
void test_weak_ptr_disconnects_self()
44+
{
45+
const auto a = new A();
46+
{
47+
sigc::internal::weak_raw_ptr<A> raw_ptr(a);
48+
49+
//Call something on A, via the weak_raw_ptr<>,
50+
//just to make sure that it doesn't get optimised away:
51+
raw_ptr->something();
52+
util->check_result(result_stream, "method called");
53+
}
54+
55+
//If the weak_raw_ptr has not asked A to stop notifying it,
56+
//then we would expect some undefined behaviour here,
57+
//when a tries to notify the now-destroyed weak_raw_ptr.
58+
delete a;
59+
}
60+
61+
int
62+
main(int argc, char* argv[])
63+
{
64+
util = TestUtilities::get_instance();
65+
66+
if (!util->check_command_args(argc, argv))
67+
return util->get_result_and_delete_instance() ? EXIT_SUCCESS : EXIT_FAILURE;
68+
69+
test_weak_ptr_becomes_null();
70+
test_weak_ptr_disconnects_self();
71+
72+
return util->get_result_and_delete_instance() ? EXIT_SUCCESS : EXIT_FAILURE;
73+
}

0 commit comments

Comments
 (0)