Skip to content

Commit 46b9dff

Browse files
committed
signal_impl: Trying to do the ref-counting with std::shared_ptr.
Bug #764935
1 parent 3527ebb commit 46b9dff

File tree

3 files changed

+23
-63
lines changed

3 files changed

+23
-63
lines changed

sigc++/signal.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ struct signal_emit
255255
* @param a Arguments to be passed on to the slots.
256256
* @return The accumulated return values of the slot invocations as processed by the accumulator.
257257
*/
258-
static decltype(auto) emit(signal_impl* impl, type_trait_take_t<T_arg>... a)
258+
static decltype(auto) emit(const std::shared_ptr<internal::signal_impl>& impl, type_trait_take_t<T_arg>... a)
259259
{
260260
using slot_iterator_buf_type = internal::slot_iterator_buf<self_type, T_return>;
261261

@@ -306,7 +306,7 @@ struct signal_emit<T_return, void, T_arg...>
306306
* @param a Arguments to be passed on to the slots.
307307
* @return The return value of the last slot invoked.
308308
*/
309-
static decltype(auto) emit(signal_impl* impl, type_trait_take_t<T_arg>... a)
309+
static decltype(auto) emit(const std::shared_ptr<internal::signal_impl>& impl, type_trait_take_t<T_arg>... a)
310310
{
311311
if (!impl || impl->slots_.empty())
312312
return T_return();
@@ -363,7 +363,7 @@ struct signal_emit<void, void, T_arg...>
363363
* passed directly on to the slots.
364364
* @param a Arguments to be passed on to the slots.
365365
*/
366-
static decltype(auto) emit(signal_impl* impl, type_trait_take_t<T_arg>... a)
366+
static decltype(auto) emit(const std::shared_ptr<internal::signal_impl>& impl, type_trait_take_t<T_arg>... a)
367367
{
368368
if (!impl || impl->slots_.empty())
369369
return;

sigc++/signal_base.cc

Lines changed: 10 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -28,27 +28,20 @@ namespace internal
2828
// when the slot is disconnected. Bug 167714.
2929
struct self_and_iter : public notifiable
3030
{
31-
signal_impl* self_;
31+
const std::shared_ptr<signal_impl> self_;
3232
const signal_impl::iterator_type iter_;
3333

34-
self_and_iter(signal_impl* self, const signal_impl::iterator_type& iter) : self_(self), iter_(iter) {}
34+
self_and_iter(const std::shared_ptr<signal_impl>& self, const signal_impl::iterator_type& iter) : self_(self), iter_(iter) {}
3535
};
3636

37-
signal_impl::signal_impl() : ref_count_(0), exec_count_(0), deferred_(false)
37+
signal_impl::signal_impl() : exec_count_(0), deferred_(false)
3838
{
3939
}
4040

4141
signal_impl::~signal_impl()
4242
{
43-
// unreference() must not call ~signal_impl() while clear() is executing.
44-
++ref_count_;
45-
4643
// Disconnect all slots before *this is deleted.
4744
clear();
48-
49-
// Now ref_count_ can be cleared again (not really necessary), but don't do it
50-
// with a call to unreference(). That would invoke ~signal_impl() recursively.
51-
--ref_count_;
5245
}
5346

5447
// only MSVC needs this to guarantee that all new/delete are executed from the DLL module
@@ -72,7 +65,7 @@ signal_impl::clear()
7265
// Don't let signal_impl::notify() erase the slots. It would invalidate the
7366
// iterator in the following loop.
7467
const bool saved_deferred = deferred_;
75-
signal_exec exec(this);
68+
signal_exec exec(shared_from_this());
7669

7770
// Disconnect all connected slots before they are deleted.
7871
// signal_impl::notify() will be called and delete the self_and_iter structs.
@@ -128,7 +121,7 @@ signal_impl::erase(iterator_type i)
128121
// Don't let signal_impl::notify() erase the slot. It would be more
129122
// difficult to get the correct return value from signal_impl::erase().
130123
const bool saved_deferred = deferred_;
131-
signal_exec exec(this);
124+
signal_exec exec(shared_from_this());
132125

133126
// Disconnect the slot before it is deleted.
134127
// signal_impl::notify() will be called and delete the self_and_iter struct.
@@ -142,7 +135,7 @@ signal_impl::erase(iterator_type i)
142135
void
143136
signal_impl::add_notification_to_iter(const signal_impl::iterator_type& iter)
144137
{
145-
auto si = new self_and_iter(this, iter);
138+
auto si = new self_and_iter(shared_from_this(), iter);
146139
iter->set_parent(si, &signal_impl::notify_self_and_iter_of_invalidated_slot);
147140
}
148141

@@ -168,7 +161,7 @@ signal_impl::sweep()
168161
// The deletion of a slot may cause the deletion of a signal_base,
169162
// a decrementation of ref_count_, and the deletion of this.
170163
// In that case, the deletion of this is deferred to ~signal_exec().
171-
signal_exec exec(this);
164+
signal_exec exec(shared_from_this());
172165

173166
deferred_ = false;
174167
auto i = slots_.begin();
@@ -207,13 +200,12 @@ signal_impl::notify_self_and_iter_of_invalidated_slot(notifiable* d)
207200

208201
} /* namespace internal */
209202

210-
signal_base::signal_base() noexcept : impl_(nullptr)
203+
signal_base::signal_base() noexcept
211204
{
212205
}
213206

214207
signal_base::signal_base(const signal_base& src) noexcept : trackable(), impl_(src.impl())
215208
{
216-
impl_->reference();
217209
}
218210

219211
signal_base::signal_base(signal_base&& src) : trackable(std::move(src)), impl_(std::move(src.impl_))
@@ -223,10 +215,6 @@ signal_base::signal_base(signal_base&& src) : trackable(std::move(src)), impl_(s
223215

224216
signal_base::~signal_base()
225217
{
226-
if (impl_)
227-
{
228-
impl_->unreference();
229-
}
230218
}
231219

232220
void
@@ -298,13 +286,7 @@ signal_base::operator=(const signal_base& src)
298286
if (src.impl_ == impl_)
299287
return *this;
300288

301-
if (impl_)
302-
{
303-
impl_->unreference();
304-
}
305-
306289
impl_ = src.impl();
307-
impl_->reference();
308290
return *this;
309291
}
310292

@@ -314,25 +296,19 @@ signal_base::operator=(signal_base&& src)
314296
if (src.impl_ == impl_)
315297
return *this;
316298

317-
if (impl_)
318-
{
319-
impl_->unreference();
320-
}
321-
322299
src.notify_callbacks();
323300
impl_ = src.impl_;
324301
src.impl_ = nullptr;
325302

326303
return *this;
327304
}
328305

329-
internal::signal_impl*
306+
std::shared_ptr<internal::signal_impl>
330307
signal_base::impl() const
331308
{
332309
if (!impl_)
333310
{
334-
impl_ = new internal::signal_impl;
335-
impl_->reference(); // start with a reference count of 1
311+
impl_ = std::make_shared<internal::signal_impl>();
336312
}
337313
return impl_;
338314
}

sigc++/signal_base.h

Lines changed: 10 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
#include <cstddef>
2323
#include <list>
24+
#include <memory> //For std::shared_ptr<>
2425
#include <sigc++config.h>
2526
#include <sigc++/type_traits.h>
2627
#include <sigc++/trackable.h>
@@ -42,7 +43,9 @@ namespace internal
4243
* erase() to sweep() when the signal is being emitted. sweep() removes all
4344
* invalid slots from the list.
4445
*/
45-
struct SIGC_API signal_impl : public notifiable
46+
struct SIGC_API signal_impl
47+
: public notifiable,
48+
public std::enable_shared_from_this<signal_impl>
4649
{
4750
using size_type = std::size_t;
4851
using slot_list = std::list<slot_base>;
@@ -64,34 +67,19 @@ struct SIGC_API signal_impl : public notifiable
6467
void operator delete(void* p);
6568
#endif
6669

67-
/// Increments the reference counter.
68-
inline void reference() noexcept { ++ref_count_; }
69-
7070
/// Increments the reference and execution counter.
7171
inline void reference_exec() noexcept
7272
{
73-
++ref_count_;
7473
++exec_count_;
7574
}
7675

77-
/** Decrements the reference counter.
78-
* The object is deleted when the reference counter reaches zero.
79-
*/
80-
inline void unreference()
81-
{
82-
if (!(--ref_count_))
83-
delete this;
84-
}
85-
8676
/** Decrements the reference and execution counter.
8777
* Invokes sweep() if the execution counter reaches zero and the
8878
* removal of one or more slots has been deferred.
8979
*/
9080
inline void unreference_exec()
9181
{
92-
if (!(--ref_count_))
93-
delete this;
94-
else if (!(--exec_count_) && deferred_)
82+
if (!(--exec_count_) && deferred_)
9583
sweep();
9684
}
9785

@@ -184,11 +172,6 @@ struct SIGC_API signal_impl : public notifiable
184172
std::list<slot_base> slots_;
185173

186174
private:
187-
/** Reference counter.
188-
* The object is destroyed when @em ref_count_ reaches zero.
189-
*/
190-
short ref_count_;
191-
192175
/** Execution counter.
193176
* Indicates whether the signal is being emitted.
194177
*/
@@ -204,7 +187,8 @@ struct SIGC_API signal_exec
204187
/** Increments the reference and execution counter of the parent sigc::signal_impl object.
205188
* @param sig The parent sigc::signal_impl object.
206189
*/
207-
inline signal_exec(const signal_impl* sig) noexcept : sig_(const_cast<signal_impl*>(sig))
190+
inline signal_exec(const std::shared_ptr<signal_impl>& sig) noexcept
191+
: sig_(sig)
208192
{
209193
sig_->reference_exec();
210194
}
@@ -220,7 +204,7 @@ struct SIGC_API signal_exec
220204

221205
protected:
222206
/// The parent sigc::signal_impl object.
223-
signal_impl* sig_;
207+
const std::shared_ptr<signal_impl> sig_;
224208
};
225209

226210
} /* namespace internal */
@@ -388,10 +372,10 @@ struct SIGC_API signal_base : public trackable
388372
/** Returns the signal_impl object encapsulating the list of slots.
389373
* @return The signal_impl object encapsulating the list of slots.
390374
*/
391-
internal::signal_impl* impl() const;
375+
std::shared_ptr<internal::signal_impl> impl() const;
392376

393377
/// The signal_impl object encapsulating the slot list.
394-
mutable internal::signal_impl* impl_;
378+
mutable std::shared_ptr<internal::signal_impl> impl_;
395379
};
396380

397381
} // namespace sigc

0 commit comments

Comments
 (0)