快速參考
以下說明如何辨識 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++ 繫結,適用於自然網域物件和連線網域物件。「自然」是指新 C++ 繫結中的自然網域物件。「Wire」是指新 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 | ||
| 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> | ||
| 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 具有設定器,每個事件宣告都會採用一個回呼。 |
||
以下是設定用戶端最常見的方式:
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,可處理這些型別,因此支援低階和高階用途。
自然類型
- 經過最佳化,可滿足高階服務程式設計的需求。
- 使用慣用的 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 繫結多。包括建構函式、解構函式、通訊協定 Proxy、通訊協定存根、複製/移動函式,以及轉換為/從就地緩衝區轉換。
- 用戶端會透過子類別化提供的虛設常式,並為每個作業實作虛擬方法,執行通訊協定分派作業。
- 系統支援非同步和同步用戶端。不過,非同步用戶端並非安全執行緒。
- 需要 C++14 以上版本。
摘要
| 類別 | 使用線路型別的新 C++ | 使用自然型別的新 C++ | 高階 C++ |
|---|---|---|---|
| 目標對象 | 驅動程式和效能關鍵應用程式 | 高階服務 | 高階服務 |
| 抽象化額外負荷 | RAII 關閉控制代碼 1 | 堆積分配量、建構、破壞 | 堆積分配量、建構、破壞 |
| 類型安全型別 | 列舉、結構體、聯集、控制代碼、通訊協定 | 列舉、結構體、聯集、控制代碼、通訊協定 | 列舉、結構體、聯集、控制代碼、通訊協定 |
| 儲存空間 | 堆疊、使用者提供的緩衝區或堆積 | 堆積 | 堆積 |
| 生命週期 | 手動或自動免費 | 自動免費 (RAII) | 自動免費 (RAII) |
| 接收行為 | 就地解碼 | 解碼為堆積 | 解碼,然後移至堆積 |
| 傳送行為 | 複製或向量化 | 複製 | 複製 |
| 呼叫通訊協定方法 | 免費函式或 Proxy | 免費函式或 Proxy | 透過 Proxy 呼叫、註冊回呼 |
| 實作通訊協定方法 | 手動調度或實作存根介面 | 實作 Stub 介面 | 實作虛設常式物件,叫用回呼 |
| 非同步用戶端 | 是 | 是 | 是 |
| 非同步伺服器 | 是 (無界限) 2 | 是 (無界) [^2] | 是 (無界限) |
| 平行伺服器調度 | 是 3 | 是 [^3] | no |
| 產生的程式碼足跡 | large | large | large |
-
產生的型別擁有所有內嵌儲存的控制代碼。當指標的包含物件消失時,系統不會關閉行外控制代碼,例如指標間接參照後方的控制代碼。在這些情況下,繫結會提供
fidl::DecodedValue物件,用於管理與呼叫相關聯的所有控制代碼。 ↩ -
lib/fidl 中定義的繫結程式庫可透過
fidl::BindServer(定義於 lib/fidl/cpp/wire/channel.h) 傳送不限數量的進行中交易。↩ -
繫結程式庫 lib/fidl 可透過 lib/fidl/cpp/wire/async_transaction.h 中定義的
EnableNextDispatch()API 啟用平行分派。↩