| Home | Libraries | People | FAQ | More

## Porting from Boost.Signals to Boost.Signals2

The changes made to the Boost.Signals2 API compared to the original Boost.Signals library are summarized below. We also provide some notes on dealing with each change while porting existing Boost.Signals code to Boost.Signals2.

- The namespace `boost::signals` has been replaced by `boost::signals2` to avoid conflict with the original Boost.Signals implementation, as well as the Qt "signals" macro. All the Boost.Signals2 classes are inside the `boost::signals2` namespace, unlike the original Boost.Signals which has some classes in the `boost` namespace in addition to its own `boost::signals` namespace.

  The Boost.Signals2 header files are contained in the `boost/signals2/` subdirectory instead of the `boost/signals` subdirectory used by the original Boost.Signals. Furthermore, all the headers except for the convenience header `boost/signals2.hpp` are inside the `boost/signals2/` subdirectory, unlike the original Boost.Signals which keeps a few headers in the parent `boost/` directory in addition to its own `boost/signals/` subdirectory.

  For example, the `signal` class is now in the `boost::signals2` namespace instead of the `boost` namespace, and it's header file is now at `boost/signals2/signal.hpp` instead of `boost/signal.hpp`.

  While porting, only trivial changes to `#include` directives and namespace qualifications should be required to deal with these changes. Furthermore, the new namespace and header locations for Boost.Signals2 allow it to coexist in the same program with the original Boost.Signals library, and porting can be performed piecemeal.

- Automatic connection management is now achieved through the use of `shared_ptr`/`weak_ptr` and `slot::track`(), as described in the tutorial. However, the old (thread-unsafe) Boost.Signals scheme of automatic connection management is still supported via the `boost::signals2::trackable` class.

  If you do not intend to make your program multi-threaded, the easiest porting path is to simply replace your uses of `boost::signals::trackable` as a base class with `boost::signals2::trackable`. Boost.Signals2 uses the same `boost::visit_each` mechanism to discover `trackable` objects as used by the original Boost.Signals library.

- Support for postconstructors (and predestructors) on objects managed by `shared_ptr` has been added with the `deconstruct` factory function. This was motivated by the importance of `shared_ptr` for the new connection tracking scheme, and the inability to obtain a `shared_ptr` to an object in its constructor. The use of `deconstruct` is described in the tutorial.

  The use of `deconstruct` is in no way required, it is only provided in the hope it may be useful. You may wish to use it if you are porting code where a class creates connections to its own member functions in its constructor, and you also wish to use the new automatic connection management scheme. You could then move the connection creation from the constructor to to the an `adl_postconstruct` function, where a reference to the owning `shared_ptr` is available for passing to `slot::track`. The `deconstruct` function would be used create objects of the class and run their associated `adl_postconstruct` function. You can enforce use of `deconstruct` by making the class' constructors private and declaring `deconstruct_access` a friend.

- The `slot` class takes a new `Signature` template parameter, is useable as a function object, and has some additional features to support the new Boost.Signals2 automatic connection management scheme.

  The changes to the slot class should generally not cause any porting difficulties, especially if you are using the `boost::signals2::trackable` compatibility class mentioned above. If you are converting your code over to use the new automatic connection management scheme, you will need to employ some of the new slot features, as described in the tutorial.

- The `optional_last_value` class has replaced `last_value` as the default combiner for signals.

  The `last_value` combiner is still provided, although its behavior is slightly changed in that it throws an exception when no slots are connected on signal invocation, instead of always requiring at least one slot to be connected (except for its void specialization which never required any slots to be connected).

  If you are porting signals which have a `void` return type in their signature and they use the default combiner, there are no changes required. If you are using the default combiner with a non-void return type and care about the value returned from signal invocation, you will have to take into account that `optional_last_value` returns a `boost::optional` instead of a plain value. One simple way to deal with this is to use `boost::optional::operator*()` to access the value wrapped inside the returned `boost::optional`.

  Alternatively, you could do a port by specifying the `Combiner` template parameter for your `signals2::signal` to be `last_value`.

- The `signal` class has an additional typedef `signal::extended_slot_type` and new `signal::connect_extended`() methods. These allow connection of slots which take an additional `connection` argument, giving them thread-safe access to their signal/slot connection when they are invoked. There is also a new `ExtendedSlotFunction` template parameter for specifying the underlying slot function type for the new extended slots.

  These additions should have no effect on porting unless you are also converting your program from a single threaded program into a multi-threaded one. In that case, if you have slots which need access to their `connection` to the signal invoking them (for example to block or disconnect their connection) you may wish to connect the slots with `signal::connect_extended`(). This also requires adding an additional connection argument to the slot. More information on how and why to use extended slots is available in the tutorial.

- The `signal` class has a new `Mutex` template parameter for specifying the mutex type used internally by the signal and its connections.

  The `Mutex` template parameter can be left to its default value of `boost::signals2::mutex` and should have little effect on porting. However, if you have a single-threaded program and are concerned about incuring a performance overhead from unneeded mutex locking, you may wish to use a different mutex for your signals such as `dummy_mutex`. See the tutorial for more information on the `Mutex` parameter.

- The `signal::combiner()` method, which formerly returned a reference to the signal's combiner has been replaced by `signal::combiner` (which now returns the combiner by value) and `signal::set_combiner`.

  During porting it should be straightforward to replace uses of the old reference-returning `signal::combiner()` function with the new "by-value" `signal::combiner` and `signal::set_combiner` functions. However, you will need to inspect each call of the `combiner` method in your code to determine if your program logic has been broken by the changed return type.

- Connections no longer have `block()` and `unblock()` methods. Blocking of connections is now accomplished by creating `shared_connection_block` objects, which provide RAII-style blocking.

  If you have existing Boost.Signals code that blocks, for example:

      namespace bs = boost::signals;

      bs::connection my_connection;
      //...

      my_connection.block();
      do_something();
      my_connection.unblock();

  then the version ported to Boost.Signals2 would look like:

      namespace bs2 = boost::signals2;

      bs2::connection my_connection;
      //...

      {
        bs2::shared_connection_block blocker(my_connection);
        do_something();
      } // blocker goes out of scope here and releases its block on my_connection

Last revised: June 12, 2007 at 14:01:23 -0400 |