GNOME Bugzilla – Bug 611941
Copied signals display unexpected behavior
Last modified: 2014-07-29 08:18:09 UTC
In essence, if you copy a sigc::signal, all of the slots that were registered on any of the copies will be triggered whenever that signal is emitted (from any of the copies). Potential solution is to simply disable copying of sigc::signals. See this mailing list thread for more information: http://mail.gnome.org/archives/gtkmm-list/2010-March/msg00013.html
In Boost.Signals2, signals are not copyable.
This surprising behaviour is documented, although quite tersely at http://developer.gnome.org/libsigc++/stable/group__signal.html: "When signals are copied they share the underlying information, so you can have a protected/private sigc::signal member and a public accessor method." I suppose this means that you can have a method like MySignal MyClass::get_my_signal(); and use the returned copy of the signal for connecting and disconnecting slots. But it's a strange motivation for the copy behaviour. An accessor that can be used for modifying the accessed object should return a reference or a pointer rather than a copy, shouldn't it?
I guess that this implicit sharing was done to avoid orphaned references or pointers.
[Resetting QA Contact and Assignee to default - see bug 659799 for more info]
sigc::signal is a reference-counting pointer in disguise. I've documented this fact more clearly. It's not a bug, it's a feature. At least it's by design. https://git.gnome.org/browse/libsigc++2/commit/?id=1b05b5a573d737e3c29056d449ebc299c26d22e3 In the gtkmm-list thread referred to in comment 0, several people have recommended that signals shall be non-copyable. That's probably easy to implement, but of course it would break API. It's not likely to occur soon. What about deprecating the copy constructor and the assignment operator? I can test if that would affect libsigc++, glibmm or gtkmm in any serious way.
Maybe if you try to make signal non-copyable then you'll find out a reason for it to be copyable. For instance, maybe it's needed to bind one signal to another. Or maybe it's not useful at all. Hopefully the tests exercise it if it's useful.
I made sigc::signal_base non-copyable and built (make && make install && make check) libsigc++2, glibmm, gtkmm, atkmm, goocanvasmm, pangomm and gtkmm-documentation. The only place where a signal is copied is in gtkmm-documentation/examples/ book/signals/custom. That example can easily be rewritten. These tests indicate that copied signals are rarely used. Still, I'm not sure it's a good idea to deprecate signal_base's copy constructor and assignment operator. Wouldn't users that feel they need a copy, be tempted to make a function that returns a pointer or a reference to the signal? That opens up the possibility for dangling pointers and references. The only problem I see with copyable signals is that it's not obvious that a sigc::signal is primarily a pointer to a reference counted signal_impl. A copy of a sigc::signal is comparable with a copy of a Glib::RefPtr<SomeClass>.
Wouldn't preventing signal copying break the common (mine too) practice of using an accessor function to get the signal. For instance, here: https://git.gnome.org/browse/glom/tree/glom/utility_widgets/notebook_noframe.h#n54 or: class Thing { public: sigc::signal<void, int> signal_something(); private: sigc::signal<void, int> m_signal_something; } We use the same technique in glibmm/gtkmm, though it's a proxy object, rather than a sigc::signal itself, that we return.
(In reply to comment #8) > Wouldn't preventing signal copying break the common (mine too) practice of > using an accessor function to get the signal. Yes, it would. The accessor function would have to return a pointer or a reference (sigc::signal<void,int>* or sigc::signal<void,int>&), and that's more error-prone. Can result in dangling pointers or dangling references. It looks like we can agree that sigc::signal shall remain copyable. The documentation I've added (see comment 5) hopefully makes it less likely that people misunderstand the meaning of the copy operation.