比较新的 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
商品结构体 自然 ::examples_keyvaluestore_baseline::Item 除了命名空间差异之外,有线类型还嵌套在“::wire”下。
电汇 ::examples_keyvaluestore_baseline::wire::Item
HLCPP ::examples::keyvaluestore::baseline::Item
WriteError 枚举 自然 ::examples_keyvaluestore_baseline::WriteError 除了命名空间差异之外,有线类型还嵌套在“::wire”下。
对于枚举和位,有线类型和自然类型是等效的。只是多了一个类型别名。
电汇 ::examples_keyvaluestore_baseline::wire::WriteError
HLCPP ::examples::keyvaluestore::baseline::WriteError
字符串: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++(线框)

  // 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++(线框)

// 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,支持低阶和高阶使用情形。

自然类型

  • 经过优化,可满足高级服务编程的需求。
  • 使用惯用的 C++ 类型(例如 std::vector、std::optional 和 std::string)表示数据结构。
  • 使用智能指针管理堆分配的对象。
  • 使用 zx::handle 管理标识名所有权。
  • 可以在其有线(例如 fidl::StringView)和自然类型表示形式(例如 std::string)之间转换数据。

电汇类型

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

客户端和服务器 API

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

请参阅新的 C++ 教程,开始行动。

高级别 C++ 绑定

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

摘要

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