summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKjell Ahlstedt <kjellahlstedt@gmail.com>2022-05-30 16:14:55 +0200
committerKjell Ahlstedt <kjellahlstedt@gmail.com>2022-05-30 16:14:55 +0200
commit8fb78907ccf3c4425d23ba1555f365f22d376685 (patch)
tree9f1a37b3ee1c3d7bd03af7e539cdaf3ad9313466
parent8668c3f8e7e09a52d4f6b0c3a389799b2a98a904 (diff)
downloadsigc++-8fb78907ccf3c4425d23ba1555f365f22d376685.tar.gz
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
-rw-r--r--sigc++/signal.h32
-rw-r--r--sigc++/signal_base.h7
-rw-r--r--tests/test_signal.cc12
3 files changed, 38 insertions, 13 deletions
diff --git a/sigc++/signal.h b/sigc++/signal.h
index 9d6143c..4a17e06 100644
--- a/sigc++/signal.h
+++ b/sigc++/signal.h
@@ -371,8 +371,14 @@ public:
} /* namespace internal */
+// TODO: When we can break ABI, let signal_base instead of signal_with_accumulator
+// derive from trackable, as in sigc++2. One of them must derive from trackable.
+// Otherwise the slot returned from signal_with_accumulator::make_slot() is not
+// automatically disconnected when the signal is deleted.
+// https://github.com/libsigcplusplus/libsigcplusplus/issues/80
+
/** Signal declaration.
- * signal_with_accumulator can be used to connect() slots that are invoked
+ * %signal_with_accumulator can be used to connect() slots that are invoked
* during subsequent calls to emit(). Any functor or slot
* can be passed into connect(). It is converted into a slot
* implicitly.
@@ -396,7 +402,9 @@ public:
* @ingroup signal
*/
template<typename T_return, typename T_accumulator, typename... T_arg>
-class signal_with_accumulator : public signal_base
+class signal_with_accumulator
+: public signal_base
+, public trackable
{
public:
using slot_type = slot<T_return(T_arg...)>;
@@ -462,11 +470,6 @@ public:
/** Creates a functor that calls emit() on this signal.
*
- * @note %sigc::signal does not derive from sigc::trackable in sigc++3.
- * If you connect the returned functor (calling %emit() on signal1) to
- * another signal (signal2) and then delete signal1, you must manually
- * disconnect signal1 from signal2 before you delete signal1.
- *
* @code
* sigc::mem_fun(mysignal, &sigc::signal_with_accumulator::emit)
* @endcode
@@ -485,19 +488,28 @@ public:
signal_with_accumulator() = default;
- signal_with_accumulator(const signal_with_accumulator& src) : signal_base(src) {}
+ signal_with_accumulator(const signal_with_accumulator& src) : signal_base(src), trackable(src) {}
- signal_with_accumulator(signal_with_accumulator&& src) : signal_base(std::move(src)) {}
+ signal_with_accumulator(signal_with_accumulator&& src)
+ : signal_base(std::move(src)), trackable(std::move(src))
+ {
+ }
signal_with_accumulator& operator=(const signal_with_accumulator& src)
{
signal_base::operator=(src);
+ // Don't call trackable::operator=(src).
+ // It calls notify_callbacks(). This signal is not destroyed.
return *this;
}
signal_with_accumulator& operator=(signal_with_accumulator&& src)
{
signal_base::operator=(std::move(src));
+ if (src.impl_ != impl_)
+ src.notify_callbacks();
+ // Don't call trackable::operator=(std::move(src)).
+ // It calls notify_callbacks(). This signal is not destroyed.
return *this;
}
};
@@ -531,7 +543,7 @@ public:
* @par Example:
* @code
* void foo(int) {}
- * sigc::signal<void, long> sig;
+ * sigc::signal<void(long)> sig;
* sig.connect(sigc::ptr_fun(&foo));
* sig.emit(19);
* @endcode
diff --git a/sigc++/signal_base.h b/sigc++/signal_base.h
index 8391782..a6da7d3 100644
--- a/sigc++/signal_base.h
+++ b/sigc++/signal_base.h
@@ -266,9 +266,10 @@ protected:
* @ref sigc::signal_with_accumulator::connect() "sigc::signal::connect()".
*/
-// TODO: When we can break ABI, let signal_base derive from trackable again.
-// It does in sigc++2. Otherwise the slot returned from signal::make_slot()
-// is not automatically disconnected when the signal is deleted.
+// TODO: When we can break ABI, let signal_base instead of signal_with_accumulator
+// derive from trackable, as in sigc++2. One of them must derive from trackable.
+// Otherwise the slot returned from signal_with_accumulator::make_slot() is not
+// automatically disconnected when the signal is deleted.
// https://github.com/libsigcplusplus/libsigcplusplus/issues/80
/** Base class for the @ref sigc::signal<T_return(T_arg...)> "sigc::signal" template.
diff --git a/tests/test_signal.cc b/tests/test_signal.cc
index d050558..34a8c7d 100644
--- a/tests/test_signal.cc
+++ b/tests/test_signal.cc
@@ -5,6 +5,7 @@
#include "testutilities.h"
#include <sigc++/trackable.h>
#include <sigc++/signal.h>
+#include <memory>
namespace
{
@@ -110,6 +111,17 @@ test_make_slot()
sig2.connect(sig.make_slot());
sig2(3);
util->check_result(result_stream, "foo(int 3) bar(float 3) foo(int 3) ");
+
+ // Delete a signal that has been connected to sig2.
+ sig2.clear();
+ sig2.connect(sigc::ptr_fun(&bar));
+ auto sig3 = std::make_unique<sigc::signal<int(int)>>();
+ sig3->connect(sigc::ptr_fun(&foo));
+ sig2.connect(sig3->make_slot());
+ sig2(2);
+ sig3.reset();
+ sig2(42);
+ util->check_result(result_stream, "bar(float 2) foo(int 2) bar(float 42) ");
}
void