比較新的 C++ 和高階 C++ 語言繫結

快速參考指引

以下說明如何識別 C++ 程式碼中的特定類型/函式/ID 是否屬於新的 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++ 繫結,且同樣適用於自然網域物件和接線網域物件。「Natural」(自然) 是指新 C++ 繫結中的自然網域物件。「線」是指新 C++ 繫結中的線路網域物件。

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
向量<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>
伺服器介面:商店
事件處理常式介面:不適用。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";

HLCPP

  // Connect to the protocol inside the component's namespace, then create an asynchronous client
  // using the newly-established connection.
  examples::canvas::baseline::InstancePtr instance_proxy;
  auto context = sys::ComponentContext::Create();
  context->svc()->Connect(instance_proxy.NewRequest(dispatcher));
  FX_LOGS(INFO) << "Outgoing connection enabled";

  instance_proxy.set_error_handler([&loop](zx_status_t status) {
    FX_LOGS(ERROR) << "Shutdown unexpectedly";
    loop.Quit();
  });

如需完整的程式碼清單和說明,請參閱畫布範例。

以下是實作伺服器最常見的方式:

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 {
    // ...
  }
};

HLCPP

// An implementation of the |Instance| protocol.
class InstanceImpl final : public examples::canvas::baseline::Instance {
  void AddLine(Line line) override {
    // ...
  }
};

如需完整的程式碼清單和說明,請參閱畫布範例。

新增 C++ 繫結

新的 C++ 繫結可提供兩個產生的網域物件系列,以及支援這些類型的對應用戶端和伺服器 API,藉此支援低階和高階用途。

自然類型

  • 經過最佳化處理,符合高階服務程式設計需求。
  • 使用慣用的 C++ 類型 (例如 std::vectorstd::optionalstd::string) 表示資料結構。
  • 使用智慧指標管理堆積分配的物件。
  • 請使用「zx::handle」管理帳號代碼擁有權。
  • 可在連接線 (例如 fidl::StringView) 和自然類型表示法 (例如 std::string) 之間轉換資料。

線型類型

  • 經過最佳化處理,可滿足低階系統程式設計的需求,同時提供比 C 繫結更多的安全性和功能略為高。
  • 代表資料結構,其記憶體版面配置與傳輸格式相同,即符合 C++ 標準版面配置。才能順利進行編碼和解碼
  • 產生的結構是基礎緩衝區的檢視畫面;它們並不擁有記憶體。
  • 支援就地存取 FIDL 訊息。
  • 讓您精細控管記憶體配置。
  • 使用自有的帳號代碼類型,例如 zx::handle。請注意,由於產生的結構是基礎緩衝區的檢視畫面,因此,只有在其本身擁有基礎緩衝區時,父項結構才會擁有子項控點。舉例來說,FIDL 結構擁有所有以內嵌儲存的控制代碼,但包含控點的 FIDL 向量向量會表示為向量檢視畫面,而且這類檢視畫面不會擁有外行控制代碼。

用戶端 API 和伺服器 API

  • 程式碼產生器產生的程式碼比 C 繫結更多。這包括建構函式、解構器、複製/移動函式、網域物件系列之間的轉換、通訊協定用戶端實作,以及純虛擬伺服器介面。
  • 使用者可將提供的伺服器介面設為子類別,並覆寫每項作業的純虛擬方法,藉此實作伺服器。
  • 支援同步處理和非同步呼叫的用戶端,以及同步和非同步事件處理作業。
  • 需要 C++17 以上版本。

如要開始使用,請參閱新 C++ 教學課程

高階 C++ 繫結

  • 經過最佳化處理,符合高階服務程式設計需求。
  • 使用慣用的 C++ 類型 (例如 std::vectorstd::optionalstd::string) 表示資料結構。
  • 使用智慧指標管理堆積分配的物件。
  • 使用 zx::handle (libzx) 管理擁有權。
  • 能將資料從現有 FIDL 緩衝區轉換為慣用的堆積已配置物件。
  • 可將資料從慣用的堆積配置物件 (例如 std::string) 轉換為就地緩衝區 (例如做為 fidl::StringView)。
  • 程式碼產生器產生的程式碼比 C 繫結更多。這包括建構函式、解構器、通訊協定 Proxy、通訊協定虛設常式、複製/移動函式,以及往返就地緩衝區的轉換。
  • 用戶端會將提供的虛設常式設為子類別,並為每個作業實作虛擬方法,藉此執行通訊協定分派作業。
  • 支援非同步和同步用戶端。然而,非同步用戶端並不安全。
  • 需要 C++14 以上版本。

如要開始使用,請參閱 HLCPP 教學課程

摘要

類別 提供傳輸類型的全新 C++ 具備自然類型的全新 C++ 高階 C++
目標對象 驅動程式和著重效能的應用程式 高階服務 高階服務
抽象層 RAII 關閉帳號代碼1 堆積分配、施工、銷毀 堆積分配、施工、銷毀
類型安全類型 列舉, 結構體, 聯集, 控制代碼, 通訊協定 列舉, 結構體, 聯集, 控制代碼, 通訊協定 列舉, 結構體, 聯集, 控制代碼, 通訊協定
儲存空間 堆疊、使用者提供的緩衝區或堆積 堆積 堆積
lifecycle 手動或自動免費 自動免費 (RAII) 自動免費 (RAII)
接收行為 就地解碼 解碼為堆積 解碼器,然後移至堆積
傳送行為 複製或向量 複製 複製
呼叫通訊協定方法 免費函式或 Proxy 免費函式或 Proxy 呼叫、註冊回呼
實作通訊協定方法 手動調度或實作虛設常式介面 實作虛設常式介面 實作虛設常式物件、叫用回呼
非同步用戶端
async server 是 (無界限) 2 是 (無界限) [^2] 是 (無界限)
平行伺服器調度 3 是 [^3]
產生的程式碼足跡

  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 啟用平行調度。