Description
libsigc++
positions itself as "The Typesafe Callback Framework for C++". However, when using sigc::track_obj
, there are some serious deficiencies in type safety that can all too easily lead to slots not auto-disconnecting.
The following code illustrates the problem. It contains four attempts to create an auto-disconnecting callback:
struct X : sigc::trackable {};
struct Y {};
X x;
Y y;
sigc::signal<void()> sig;
sig.connect(sigc::track_obj([] {}, x)); // good
sig.connect(sigc::track_obj([] {}, y)); // bad but compiles
sig.connect(sigc::track_obj([] {}, &x)); // bad but compiles
sig.connect(sigc::track_obj([] {}, 42)); // bad but compiles
- The first is the correct way. It auto-disconnects when
x
is destructed. - Should not be allowed, as
Y
is notsigc::trackable
, so cannot auto-disconnect. - This both looks plausible and compiles, but does not auto-disconnect.
- Shouldn't even compile, but does so without a hitch.
This behaviour makes sigc::track_obj
extremely fragile and dangerous. Code using sigc::track_obj
for auto-disconnection can start silently failing when the programmer changes a type, as shown by point 2. It is also extremely easy to use incorrectly without the slightest indication something is wrong, as shown by point 3. For safety reasons, code using sigc::track_obj
should only compile if auto-disconnection will actually happen. In particular, examples 2-4 should not compile.