Skip to content

Commit 8fb7890

Browse files
committed
signal_with_accumulator derives from trackable
A slot made with signal_with_accumulator::make_slot() is then automatically disconnected when the signal is deleted, as in sigc++2. Fixes #80
1 parent 8668c3f commit 8fb7890

File tree

3 files changed

+38
-13
lines changed

3 files changed

+38
-13
lines changed

sigc++/signal.h

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -371,8 +371,14 @@ struct signal_emit<void, void, T_arg...>
371371

372372
} /* namespace internal */
373373

374+
// TODO: When we can break ABI, let signal_base instead of signal_with_accumulator
375+
// derive from trackable, as in sigc++2. One of them must derive from trackable.
376+
// Otherwise the slot returned from signal_with_accumulator::make_slot() is not
377+
// automatically disconnected when the signal is deleted.
378+
// https://github.com/libsigcplusplus/libsigcplusplus/issues/80
379+
374380
/** Signal declaration.
375-
* signal_with_accumulator can be used to connect() slots that are invoked
381+
* %signal_with_accumulator can be used to connect() slots that are invoked
376382
* during subsequent calls to emit(). Any functor or slot
377383
* can be passed into connect(). It is converted into a slot
378384
* implicitly.
@@ -396,7 +402,9 @@ struct signal_emit<void, void, T_arg...>
396402
* @ingroup signal
397403
*/
398404
template<typename T_return, typename T_accumulator, typename... T_arg>
399-
class signal_with_accumulator : public signal_base
405+
class signal_with_accumulator
406+
: public signal_base
407+
, public trackable
400408
{
401409
public:
402410
using slot_type = slot<T_return(T_arg...)>;
@@ -461,11 +469,6 @@ class signal_with_accumulator : public signal_base
461469
}
462470

463471
/** Creates a functor that calls emit() on this signal.
464-
*
465-
* @note %sigc::signal does not derive from sigc::trackable in sigc++3.
466-
* If you connect the returned functor (calling %emit() on signal1) to
467-
* another signal (signal2) and then delete signal1, you must manually
468-
* disconnect signal1 from signal2 before you delete signal1.
469472
*
470473
* @code
471474
* sigc::mem_fun(mysignal, &sigc::signal_with_accumulator::emit)
@@ -485,19 +488,28 @@ class signal_with_accumulator : public signal_base
485488

486489
signal_with_accumulator() = default;
487490

488-
signal_with_accumulator(const signal_with_accumulator& src) : signal_base(src) {}
491+
signal_with_accumulator(const signal_with_accumulator& src) : signal_base(src), trackable(src) {}
489492

490-
signal_with_accumulator(signal_with_accumulator&& src) : signal_base(std::move(src)) {}
493+
signal_with_accumulator(signal_with_accumulator&& src)
494+
: signal_base(std::move(src)), trackable(std::move(src))
495+
{
496+
}
491497

492498
signal_with_accumulator& operator=(const signal_with_accumulator& src)
493499
{
494500
signal_base::operator=(src);
501+
// Don't call trackable::operator=(src).
502+
// It calls notify_callbacks(). This signal is not destroyed.
495503
return *this;
496504
}
497505

498506
signal_with_accumulator& operator=(signal_with_accumulator&& src)
499507
{
500508
signal_base::operator=(std::move(src));
509+
if (src.impl_ != impl_)
510+
src.notify_callbacks();
511+
// Don't call trackable::operator=(std::move(src)).
512+
// It calls notify_callbacks(). This signal is not destroyed.
501513
return *this;
502514
}
503515
};
@@ -531,7 +543,7 @@ class signal_with_accumulator : public signal_base
531543
* @par Example:
532544
* @code
533545
* void foo(int) {}
534-
* sigc::signal<void, long> sig;
546+
* sigc::signal<void(long)> sig;
535547
* sig.connect(sigc::ptr_fun(&foo));
536548
* sig.emit(19);
537549
* @endcode

sigc++/signal_base.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -266,9 +266,10 @@ struct SIGC_API signal_impl_holder
266266
* @ref sigc::signal_with_accumulator::connect() "sigc::signal::connect()".
267267
*/
268268

269-
// TODO: When we can break ABI, let signal_base derive from trackable again.
270-
// It does in sigc++2. Otherwise the slot returned from signal::make_slot()
271-
// is not automatically disconnected when the signal is deleted.
269+
// TODO: When we can break ABI, let signal_base instead of signal_with_accumulator
270+
// derive from trackable, as in sigc++2. One of them must derive from trackable.
271+
// Otherwise the slot returned from signal_with_accumulator::make_slot() is not
272+
// automatically disconnected when the signal is deleted.
272273
// https://github.com/libsigcplusplus/libsigcplusplus/issues/80
273274

274275
/** Base class for the @ref sigc::signal<T_return(T_arg...)> "sigc::signal" template.

tests/test_signal.cc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "testutilities.h"
66
#include <sigc++/trackable.h>
77
#include <sigc++/signal.h>
8+
#include <memory>
89

910
namespace
1011
{
@@ -110,6 +111,17 @@ test_make_slot()
110111
sig2.connect(sig.make_slot());
111112
sig2(3);
112113
util->check_result(result_stream, "foo(int 3) bar(float 3) foo(int 3) ");
114+
115+
// Delete a signal that has been connected to sig2.
116+
sig2.clear();
117+
sig2.connect(sigc::ptr_fun(&bar));
118+
auto sig3 = std::make_unique<sigc::signal<int(int)>>();
119+
sig3->connect(sigc::ptr_fun(&foo));
120+
sig2.connect(sig3->make_slot());
121+
sig2(2);
122+
sig3.reset();
123+
sig2(42);
124+
util->check_result(result_stream, "bar(float 2) foo(int 2) bar(float 42) ");
113125
}
114126

115127
void

0 commit comments

Comments
 (0)