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::signals2::trackable 类来实现旧的(线程不安全)Boost.Signals 自动连接管理方案。

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

  • 通过 deconstruct 工厂函数,增加了对 shared_ptr 管理的对象的后构造函数(和前析构函数)的支持。这是由于 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 组合器,但其行为略有变化,即在信号调用时未连接任何槽时会抛出异常,而不是始终要求至少连接一个槽(其 void 特化除外,它从不需要连接任何槽)。

    如果您正在移植签名中具有 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 参数的槽,从而使它们在被调用时可以线程安全地访问其信号/槽连接。还有一个新的 ExtendedSlotFunction 模板参数,用于为新的扩展槽指定底层槽函数类型。

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

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

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

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

    在移植过程中,将旧的返回引用的 signal::combiner() 函数替换为新的“按值” signals2::signal::combinersignals2::signal::set_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 是第一个包含 Signals2 库的 Boost 版本。


PrevUpHomeNext