...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
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 |