比较新的 C++ 和高级 C++ 语言绑定

快速参考

下面介绍了如何识别 C++ 代码中的特定类型/函数/标识符是否属于新的 C++ 绑定或高级 C++ 绑定。

examples.keyvaluestore.baseline 库为例:

library examples.keyvaluestore.baseline;

type Item = struct {
    key string:128;
    value vector<byte>:64000;
};

type WriteError = flexible enum {
    UNKNOWN = 0;
    INVALID_KEY = 1;
    INVALID_VALUE = 2;
    ALREADY_EXISTS = 3;
};

@discoverable
open protocol Store {
    /// Writes an item to the store.
    flexible WriteItem(struct {
        attempt Item;
    }) -> () error WriteError;
};

下面介绍了各种 FIDL 元素在 C++ 绑定中的映射方式。请注意,在表格中,“C++”是指新的 C++ 绑定,同样适用于自然域对象和线程域对象。“自然”是指新 C++ 绑定中的自然网域对象。“Wire”是指新 C++ 绑定中的 Wire 域对象。

FIDL 元素 C++ 自然类型 评论
头文件包含 C++ #include <fidl/examples.keyvaluestore.baseline/cpp/fidl.h> 格式为 `fidl/library name/cpp/fidl.h`
HLCPP #include <examples/keyvaluestore/baseline/cpp/fidl.h> 格式为“以斜线分隔的库名称/cpp/fidl.h”
C++ ::examples_keyvaluestore_baseline 新 C++ 使用单级命名空间。
HLCPP 使用嵌套命名空间。
HLCPP ::examples::keyvaluestore::baseline
Item 结构体 自然 ::examples_keyvaluestore_baseline::Item 除了命名空间差异之外,线程类型还嵌套在“::wire”下。
线 ::examples_keyvaluestore_baseline::wire::Item
HLCPP ::examples::keyvaluestore::baseline::Item
WriteError 枚举 自然 ::examples_keyvaluestore_baseline::WriteError 除了命名空间差异之外,线程类型还嵌套在“::wire”下。
对于枚举和位,线程类型和自然类型是等效的。只是多了一个类型别名。
Wire ::examples_keyvaluestore_baseline::wire::WriteError
HLCPP ::examples::keyvaluestore::baseline::WriteError
string:128 自然 std::string
线 fidl::StringView
HLCPP std::string
vector<byte>:64000 自然 std::vector<uint8_t>
线 fidl::VectorView<uint8_t>
HLCPP std::vector<uint8_t>
协议存储 C++ ::examples_keyvaluestore_baseline::Store 一种标记类型,用于携带与协议相关的一些信息
HLCPP ::examples::keyvaluestore::baseline::Store 包含协议中方法的抽象基类
client_end:Store C++ fidl::ClientEnd<Store>
HLCPP fidl::InterfaceHandle<Store>
server_end:Store C++ fidl::ServerEnd<Store>
HLCPP fidl::InterfaceRequest<Store>

商店协议的客户端和服务器类型
自然 客户端:fidl::Client<Store>
同步客户端:fidl::SyncClient<Store>
服务器接口:fidl::Server<Store>
事件处理脚本接口:fidl::EventHandler<Store>
线 客户端:fidl::WireClient<Store>
同步客户端:fidl::WireSyncClient<Store>
服务器接口:fidl::WireServer<Store>
事件处理脚本接口:fidl::WireEventHandler<Store>
HLCPP 客户端:fidl::InterfacePtr<Store>
同步客户端:fidl::SynchronousInterfacePtr<Store>
服务器接口:Store
事件处理脚本接口:不适用。InterfacePtr 具有每个事件声明一个回调的 setter。

以下是最常见的客户端设置方式:

C++(自然)

  // Connect to the protocol inside the component's namespace. This can fail so it's wrapped in a
  // |zx::result| and it must be checked for errors.
  zx::result client_end = component::Connect<examples_canvas_baseline::Instance>();
  if (!client_end.is_ok()) {
    FX_LOGS(ERROR) << "Synchronous error when connecting to the |Instance| protocol: "
                   << client_end.status_string();
    return -1;
  }

  // Create an instance of the event handler.
  EventHandler event_handler(loop);

  // Create an asynchronous client using the newly-established connection.
  fidl::Client client(std::move(*client_end), dispatcher, &event_handler);
  FX_LOGS(INFO) << "Outgoing connection enabled";

C++ (Wire)

  // Connect to the protocol inside the component's namespace. This can fail so it's wrapped in a
  // |zx::result| and it must be checked for errors.
  zx::result client_end = component::Connect<examples_canvas_baseline::Instance>();
  if (!client_end.is_ok()) {
    FX_LOGS(ERROR) << "Synchronous error when connecting to the |Instance| protocol: "
                   << client_end.status_string();
    return -1;
  }

  // Create an instance of the event handler.
  EventHandler event_handler(loop);

  // Create an asynchronous client using the newly-established connection.
  fidl::WireClient client(std::move(*client_end), dispatcher, &event_handler);
  FX_LOGS(INFO) << "Outgoing connection enabled";

如需查看完整的代码列表和说明,请参阅 canvas 示例。

下面是最常见的服务器实现方式:

C++(自然)

// An implementation of the |Instance| protocol.
class InstanceImpl final : public fidl::Server<examples_canvas_baseline::Instance> {
  void AddLine(AddLineRequest& request, AddLineCompleter::Sync& completer) override {
    // ...
  }
};

C++ (Wire)

// An implementation of the |Instance| protocol.
class InstanceImpl final : public fidl::WireServer<examples_canvas_baseline::Instance> {
  void AddLine(AddLineRequestView request, AddLineCompleter::Sync& completer) override {
    // ...
  }
};

如需查看完整的代码列表和说明,请参阅 canvas 示例。

新的 C++ 绑定

新的 C++ 绑定通过提供两类生成的网域对象以及使用这些类型的相应客户端和服务器 API,同时支持低级和高级用例。

自然类型

  • 经过优化,可满足高级服务编程需求。
  • 使用 std::vectorstd::optionalstd::string 等惯用 C++ 类型表示数据结构。
  • 使用智能指针管理堆分配的对象。
  • 使用 zx::handle 管理句柄所有权。
  • 可以在线程 (fidl::StringView) 和自然类型表示法 (std::string) 之间转换数据。

线类型

  • 经过优化,可满足低级系统编程需求,同时提供比 C 绑定稍高的安全性和功能。
  • 表示内存布局与线格格式一致(即满足 C++ 标准布局)的数据结构。这为原地编码和解码打开了大门。
  • 生成的结构是底层缓冲区的视图;它们不拥有内存。
  • 支持对 FIDL 消息的内嵌访问。
  • 对内存分配提供精细控制。
  • 使用自有句柄类型,例如 zx::handle。请注意,由于生成的结构是底层缓冲区的视图,因此父结构只有在拥有其底层缓冲区的情况下,才会拥有子句柄。例如,一个 FIDL 结构体拥有内嵌存储的所有句柄,但包含句柄的结构体 FIDL 矢量将表示为矢量视图,该视图不会拥有线外句柄。

客户端和服务器 API

  • 与 C 绑定相比,代码生成器会生成更多代码。这包括构造函数、析构函数、复制/移动函数、网域对象族之间的转换、协议客户端实现和纯虚拟服务器接口。
  • 用户通过对提供的服务器接口进行子类化并替换每个操作的纯虚方法来实现服务器。
  • 支持同步和异步调用以及同步和异步事件处理的客户端。
  • 需要 C++17 或更高版本。

请参阅“新手入门”C++ 教程,开始行动。

高级 C++ 绑定

  • 经过优化,可满足高级服务编程需求。
  • 使用 std::vectorstd::optionalstd::string 等惯用 C++ 类型表示数据结构。
  • 使用智能指针管理堆分配的对象。
  • 使用 zx::handle (libzx) 管理句柄所有权。
  • 可以将数据从就地 FIDL 缓冲区转换为惯用堆分配对象。
  • 可以将数据从惯用堆分配的对象(例如 std::string)转换为原地缓冲区(例如 fidl::StringView)。
  • 与 C 绑定相比,代码生成器会生成更多代码。这包括构造函数、析构函数、协议代理、协议桩、复制/移动函数,以及对原地缓冲区的转换。
  • 客户端通过对提供的桩进行子类化并为每个操作实现虚拟方法来执行协议调度。
  • 支持异步和同步客户端。不过,异步客户端并非线程安全的。
  • 需要 C++14 或更高版本。

摘要

类别 新增了带有线类型的 C++ 具有自然类型的新 C++ 高级 C++
受众群体 驱动程序和性能关键型应用 高级服务 高级服务
抽象开销 RAII 关闭句柄 1 堆分配、构建、销毁 堆分配、构建、销毁
类型安全类型 枚举、结构体、联合体、句柄、协议 枚举、结构体、联合体、句柄、协议 枚举、结构体、联合体、句柄、协议
storage 堆栈、用户提供的缓冲区或堆
lifecycle 手动或自动免费 自动释放 (RAII) 自动释放 (RAII)
接收行为 就地解码 解码到堆 解码,然后移至堆
发送行为 复制或矢量化 复制 复制
调用协议方法 自由函数或代理 自由函数或代理 通过代理进行调用、注册回调
实现协议方法 手动调度或实现桩接口 实现桩接口 实现桩对象,调用回调
异步客户端
异步服务器 是(无上限)2 是(无上限)[^2] 是(无上限)
并行服务器调度 3 yes [^3]
生成的代码占用空间 large large large

  1. 生成的类型拥有内嵌存储的所有句柄。当指针的包含对象消失时,线下手柄(例如指针指向后面的手柄)不会关闭。在这些情况下,绑定会提供一个 fidl::DecodedValue 对象来管理与调用相关联的所有句柄。 

  2. lib/fidl 中定义的绑定库可以通过 lib/fidl/cpp/wire/channel.h 中定义的 fidl::BindServer 调度数量不受限的正在处理的交易。

  3. 绑定库 lib/fidl 使用 lib/fidl/cpp/wire/async_transaction.h 中定义的 EnableNextDispatch() API 启用并发调度。