Skip to content
Tags

,

ScopeGuard for signals: first try

by razvanpetru on March 8th, 2010

While working with state machines in Qt I have encountered the typical situation where a state can be exited through a “fail” transition or a “success” transition. In my case, both transitions were triggered by signals and the signals were emitted from a checker function.

The success transition was easy since there’s usually only one way to do things right, but the failure transition could be triggered from multiple places inside the checker function. Every few lines I would check for some condition, do a few things, emit failed(), and return. Every few other lines I would forget to emit failed() and get some interesting bugs. Fun as that was, I got tired of it pretty fast… hence SignalGuard!

SignalGuard is a ScopeGuard that works with the moc and signals instead of template tricks and arbitrary functions. It automatically emits a signal when the SignalGuard object is destroyed, simplifying emits when dealing with multiple exit points.

Here’s a quick example:

SignalGuard cancelGuard(this, SIGNAL(requestCanceled()));
// do check one, if failed show a message, return
// do check two, if failed show a message, return
// do check three, if failed show a message, return
cancelGuard.dismiss(); // phew, we've made it

The signal guard will automatically emit requestCanceled when it is destroyed unless we dismiss() it. A maintenance programmer that will add other checks won’t introduce a subtle bug by forgetting to emit the canceled signal and the code is cleaner too!

Here’s another example:

emit uiWait(); // show a busy cursor
foo();
bar();
emit uiFinishWait(); // show a regular cursor

Without SignalGuard, we’d probably have to rewrite the above code or risk being stuck with an hourglass cursor:

emit uiWait();
try
{
  foo();
  bar(); // what if this throws?
}
catch( std::exception& )
{
  emit uiFinishWait();
  throw;
}
emit uiFinishWait();

But why complicate the control flow when you could write this instead:

SignalGuard g(this, SIGNAL(uiFinishWait()));
emit uiWait();
foo();
bar();

That’s about all that SignalGuard does right now. You can download the sources from my brand new bitbucket repository. The code is really simple – that’s why this is labeled first try – but I’d like to extend it to allow specifying the connection type (easy) and signals/slots with parameters (tricky, I need the parameter types).

From → Programming

One Comment
  1. badone permalink

    RAII strikes again.

    Nicely done, has a lot of potential.

Comments are closed.