Boost C++ 库

“……世界上最受尊敬和设计最精良的 C++ 库项目之一。” Herb SutterAndrei Alexandrescu, C++ 编码标准

PrevUpHomeNext

Signals2 API 变更

从 Boost.Signals 移植到 Boost.Signals2
Signals2 API 开发

从 Boost.Signals 移植到 Boost.Signals2

下面总结了 Boost.Signals2 API 相对于原始 Boost.Signals 库所做的更改。 我们还提供了一些关于在将现有 Boost.Signals 代码移植到 Boost.Signals2 时处理每个更改的注意事项。

  • 命名空间 boost::signals 已被 boost::signals2 替换,以避免与原始 Boost.Signals 实现以及 Qt "signals" 宏冲突。 所有 Boost.Signals2 类都在 boost::signals2 命名空间内,这与原始 Boost.Signals 不同,后者除了自己的 boost::signals 命名空间外,还有一些类在 boost 命名空间中。

    Boost.Signals2 头文件包含在 boost/signals2/ 子目录中,而不是原始 Boost.Signals 使用的 boost/signals 子目录。 此外,除了便利头文件 boost/signals2.hpp 之外,所有头文件都在 boost/signals2/ 子目录内,这与原始 Boost.Signals 不同,后者除了自己的 boost/signals/ 子目录外,还保留了一些头文件在父 boost/ 目录中。

    例如,signal 类现在位于 boost::signals2 命名空间中,而不是 boost 命名空间中,并且它的头文件现在位于 boost/signals2/signal.hpp 而不是 boost/signal.hpp

    在移植过程中,只需要对 #include 指令和命名空间限定符进行简单的更改即可处理这些更改。 此外,Boost.Signals2 的新命名空间和头文件位置允许它与原始 Boost.Signals 库在同一程序中共存,并且可以逐步执行移植。

  • 现在,通过使用 shared_ptr/weak_ptrsignals2::slot::track() 来实现自动连接管理,如 教程中所述。 但是,旧的(线程不安全)Boost.Signals 自动连接管理方案仍然通过 boost::signals2::trackable 类支持。

    如果您不打算使您的程序多线程化,则最简单的移植路径是简单地将您使用的 boost::signals::trackable 作为基类替换为 boost::signals2::trackable。 Boost.Signals2 使用相同的 boost::visit_each 机制来发现 trackable 对象,就像原始 Boost.Signals 库所使用的那样。

  • 通过 shared_ptr 管理的对象上的后构造函数(和预析构函数)的支持已通过 deconstruct 工厂函数添加。 这是由 shared_ptr 对于新的连接跟踪方案的重要性以及无法在其构造函数中获得对象的 shared_ptr 驱动的。 deconstruct 的使用在 教程中进行了描述。

    绝不需要使用 deconstruct,它只是被提供,希望它可能有用。 如果您正在移植一个类在其构造函数中创建与其自身成员函数的连接的代码,并且您还希望使用新的自动连接管理方案,那么您可能希望使用它。 然后,您可以将连接创建从构造函数移动到 adl_postconstruct 函数,其中可以获得对拥有的 shared_ptr 的引用,以传递给 signals2::slot::trackdeconstruct 函数将用于创建类的对象并运行其关联的 adl_postconstruct 函数。 您可以通过使类的构造函数私有并将 deconstruct_access 声明为友元来强制使用 deconstruct

  • signals2::slot 类采用一个新的 Signature 模板参数,可以用作函数对象,并且具有一些附加功能来支持新的 Boost.Signals2 自动连接管理方案。

    对 slot 类的更改通常不会导致任何移植困难,特别是如果您使用上面提到的 boost::signals2::trackable 兼容性类。 如果您正在将您的代码转换为使用新的自动连接管理方案,您将需要使用一些新的 slot 功能,如 教程中所述。

  • optional_last_value 类已替换 last_value 作为信号的默认组合器。

    仍然提供了 signals2::last_value 组合器,尽管它的行为略有改变,因为它在信号调用时没有连接任何 slot 时会抛出异常,而不是总是要求至少连接一个 slot(除了它的 void 特化,它从不需要连接任何 slot)。

    如果您正在移植的信号在其签名中具有 void 返回类型,并且它们使用默认组合器,则不需要进行任何更改。 如果您使用具有非 void 返回类型的默认组合器并且关心从信号调用返回的值,您将必须考虑到 optional_last_value 返回一个 boost::optional 而不是一个普通值。 处理这个问题的一个简单方法是使用 boost::optional::operator*() 来访问包装在返回的 boost::optional 中的值。

    或者,您可以通过指定 signals2::signalCombiner 模板参数为 signals2::last_value 来进行移植。

  • signals2::signal 类有一个额外的 typedef signals2::signal::extended_slot_type 和新的 signals2::signal::connect_extended() 方法。 这些允许连接采用额外的 signals2::connection 参数的 slot,从而在调用它们时为它们提供对其信号/slot 连接的线程安全访问。 还有一个新的 ExtendedSlotFunction 模板参数,用于指定新的扩展 slot 的底层 slot 函数类型。

    除非您还将您的程序从单线程程序转换为多线程程序,否则这些添加不应影响移植。 在这种情况下,如果您有需要访问调用它们的信号的 signals2::connection 的 slot(例如,阻止或断开它们的连接),您可能希望使用 signals2::signal::connect_extended() 连接 slot。 这还需要向 slot 添加一个额外的连接参数。 有关如何以及为什么要使用扩展 slot 的更多信息,请参见 教程

  • signals2::signal 类有一个新的 Mutex 模板参数,用于指定信号及其连接内部使用的互斥锁类型。

    Mutex 模板参数可以保留其默认值 boost::signals2::mutex,并且对移植的影响应该很小。 但是,如果您有一个单线程程序并且担心不必要的互斥锁锁定会产生性能开销,您可能希望为您的信号使用不同的互斥锁,例如 dummy_mutex。 有关 Mutex 参数的更多信息,请参见 教程

  • signal::combiner() 方法,该方法以前返回对信号组合器的引用,已被 signals2::signal::combiner(现在按值返回组合器)和 signals2::signal::set_combiner 替换。

    在移植过程中,应该可以直接使用新的“按值” signals2::signal::combinersignals2::signal::set_combiner 函数替换旧的返回引用的 signal::combiner() 函数。 但是,您需要检查代码中对 combiner 方法的每个调用,以确定您的程序逻辑是否因更改的返回类型而损坏。

  • 连接不再具有 block()unblock() 方法。 现在通过创建 shared_connection_block 对象来实现连接的阻止,这些对象提供 RAII 样式的阻止。

    如果您有现有的 Boost.Signals 代码阻止,例如

      namespace bs = boost::signals;
    
      bs::connection my_connection;
      //...
    
      my_connection.block();
      do_something();
      my_connection.unblock();
      

    那么移植到 Boost.Signals2 的版本将如下所示

      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
      

Signals2 API 开发

版本 1.56

1.56 版本修改了信号析构函数的行为,不再显式调用 disconnect_all_slots。任何与信号析构函数并发运行的信号调用现在应该正常完成,而不是跳过所有剩余的槽。一旦所有并发信号调用完成,与已删除信号的所有连接最终仍将被断开。此更改使 Boost.Signals2 的行为更接近原始 Boost.Signals 库的行为。

1.45 版本

1.45 版本添加了 slot::track_foreign()。此方法允许跟踪由 shared_ptr 类(而非 boost::shared_ptr)拥有的对象,例如 std::shared_ptr

1.40 版本

1.40 版本为 shared_connection_block 类添加了一些新特性,使其更加灵活

1.40 版本还引入了 Signals2 的可变参数模板实现,当 Boost 检测到编译器支持可变参数模板时(可变参数模板是 C++11 的一项新特性)将使用该实现。此更改对用户来说大多是透明的,但它确实对接口引入了一些可见的调整,如下所述。

以下库特性已被弃用,仅当您的编译器未使用可变参数模板时可用(即 Boost.Config 定义了 BOOST_NO_CXX11_VARIADIC_TEMPLATES)。

1.39 版本

1.39 版本是 Boost 包含 Signals2 库的第一个版本。


PrevUpHomeNext