本文件概述可用於管理記憶體的工具 使用新 C++ 繫結的線域物件。
Wire 網域物件在維護效能方面十分安全
C++ 繫結的線域物體 (也稱為「線型」) 是精簡的
以及記憶體佈局符合
來源 *.fidl
類型的 FIDL 線格式密切
。提供便利的包裝函式和存取子,但未提供
來封裝基本線路格式的結構。使用這項
欄位通常可以就地存取
並序列化資料
複製。瞭解 FIDL 線段的配置
有助於解決通訊類型問題特別是電線類型。
沒有自己的線上子項 (根據 FIDL 線格式的定義)。
線路類型會使用以下方式保留對物件的非從屬參照:
- 如果是字串,
fidl::StringView
。 - 如果是物件向量,
fidl::VectorView
。 - 如果是線外物件,則為
fidl::ObjectView
。 - 針對名為
Foo
的資料表,這個Foo
類別包含向量檢視,並參照 一組以fidl::WireTableFrame<Foo>
表示的信封標頭。 然後參照表格的欄位 - 針對名為
Foo
的聯集,這個Foo
類別可用於儲存序數和 信封標頭:- 小於 4 個位元組的小型欄位會使用內嵌表示法,且 。
- 較大欄位 >4 個位元組使用非線表示儲存的內容 。
- 如果是
MyMethod
要求訊息,則納入指標的MyMethodRequestView
加到要求中這個定義的範圍僅限於fidl::WireServer<Protocol>
類別。
使用 inline 這類非擁有檢視畫面,只會保留參考資料, 不會管理物件生命週期物件的生命週期必須受到管理 外部。這表示參照的物件必須在檢視畫面的生命週期內。
複製檢視表會為檢視表中的參照建立別名。移動視圖是 且不會清除來源檢視畫面。
基於記憶體安全原因的資料表,無法變更。 資料表會傳回空白資料表。如要建立含有欄位的資料表,您必須使用 建立工具資料表的成員可以變動,但無法新增或移除 建立的成員。
為了與資料表簡單一致,聯集也無法變更。他們的
預設建構函式會將其置於缺少狀態中。無法傳送執行階段錯誤
除非在程式庫定義中將聯集標示為 optional
,否則就不會建立聯集。
如要取得含有 bar
成員的聯集 Foo
,請呼叫靜態工廠函式
Foo::WithBar(...)
。引數可以是
信封)、值的 fidl::ObjectView
(較大值) 或
的不分詞和建構函式引數。
fidl::StringView
定義於 lib/fidl/cpp/wire/string_view.h
保留儲存在緩衝區中變數長度字串的參照。C++ fidl_string 的包裝函式。並未擁有內容的記憶體。
如要建構 fidl::StringView
,請提供指標和數量
分別使用 UTF-8 位元組 (結尾的 \0
除外)。除此之外
C++ 字串常值,或任何實作 [const] char* data()
的值
和 size()
。字串檢視畫面會借用容器的內容。
此為與 fidl_string 相容的記憶體配置。
fidl::VectorView<T>
定義於 lib/fidl/cpp/wire/vector_view.h
保留儲存在 緩衝區。fidl_vector 的 C++ 包裝函式。不具備元素記憶體。
如要建構 fidl::VectorView
,請提供指標和數量
或者,您也可以傳送支援
std::data
,例如:
標準容器或陣列向量檢視畫面會借用
此為與 fidl_vector 相容的記憶體配置。
fidl::Array<T, N>
擁有固定長度的元素陣列。這個路徑與 std::array<T, N>
類似,但
設計為與 FIDL 陣列和標準版面配置相容的記憶體版面配置。
在適用情況下,解構函式關閉後會隨即關閉,例如:帳號代碼的 fidl::Array
。
要求/回應處理常式中的訊息檢視畫面
伺服器實作中的要求處理常式接收要求的檢視 撰寫新的電子郵件訊息使用者不擁有支援檢視畫面的緩衝區。
要求檢視表背後的資料一定會保存到 方法。因此,如果伺服器想要以非同步方式提供回覆, 並在回覆中使用要求訊息時,使用者需要複製相關的 來自要求訊息到自有儲存空間的欄位:
// A FIDL method called "StartGame".
virtual void StartGame(
StartGameRequestView request, StartGameCompleter::Sync completer) {
// Suppose the request has a `foo` field that is a string view,
// we need to copy it to an owning type e.g. |std::string|.
auto foo = std::string(request->foo.get());
// Make an asynchronous reply using the owning type.
async::PostDelayedTask(
dispatcher_,
[foo = std::move(foo), completer = completer.ToAsync()]() mutable {
// As an example, we simply echo back the string.
completer.Reply(fidl::StringView::FromExternal(foo));
});
}
同樣地,傳遞至用戶端的回應處理常式與事件處理常式也僅 收到回應/活動訊息的檢視畫面複製到使用者擁有的儲存空間 如果需要在處理常式傳回後加以存取,則需要 450 個字元:
// Suppose the response has a `bar` field that is a table:
//
// type Bar = table {
// 1: a uint32;
// 2: b string;
// };
//
// we need to copy the table to an owned type by copying each element.
struct OwnedBar {
std::optional<uint32_t> a;
std::optional<std::string> b;
};
// Suppose we are in a class that has a `OwnedBar bar_` member.
client_->MakeMove(args).Then([](fidl::WireUnownedResult<TicTacToe::MakeMove>& result) {
assert(result.ok());
auto* response = result.Unwrap();
// Create an owned value and copy the wire table into it.
OwnedBar bar;
if (response->bar.has_a())
bar.a = response->bar.a();
if (response->bar.has_b())
bar.b = std::string(response->bar.b().get());
bar_ = std::move(bar);
});
建立線形檢視畫面和物件
整體而言,建立線路物件的方式有兩種:使用競技場,或 以不安全的方式借用記憶體使用競技場通常比較安全,且在多數 用途以不安全的方式借用記憶體很容易出錯和損毀,但 需要控制每個單一位元組配置時呼叫
使用 Areas 建立線路物件
Wire 物件會與物件介面 fidl::AnyArena
整合,通常是在
建構函式或工廠函式,可讓使用者
分配行為FIDL 執行階段提供了標準實作
物件介面,fidl::Arena
。競技場會管理分配的生命週期
線物體 (擁有者為物體)。這個運動場遭到毀滅後
其配置的物件會被取消配置,並且呼叫它們的解構函式。
fidl::Arena
是在 lib/fidl/cpp/wire/arena.h 中定義。
物件會先在屬於該場地的緩衝區內配置 (
物件的內嵌欄位)。緩衝區的預設大小為 512 個位元組。A 罩杯
您可以使用 fidl::Arena<size>
選取不同大小。如果微調這個大小
任何在要求期間建立的配置物件
進而避免配置昂貴的堆積分配量
當內嵌緩衝區已滿時,競技場會在堆積上分配更多緩衝區。 每個緩衝區皆為 16 KiB。如果其中一個需要大於 16 KiB 的物件, 競技場會使用客製化緩衝區,同時有足夠的空間 大小
使用競技場的標準模式如下:
- 定義
fidl::Arena
類型的本機變數領域。 - 使用競技場分配物件。
- 呼叫 FIDL 方法或回覆訊息,即可傳送分配的物件 提供完整解答
- 結束函式範圍後,所有這些本機變數都會 自動取消分配
競技場需要超越所有參照其中物件的檢視畫面類型。
如要查看註解,請參閱傳輸網域物件教學課程 舉例說明如何運用競技場實際建立資料表、聯集等。
建立線路檢視畫面借用未擁有的資料
除了受管理的分配策略,您也可以
直接向 FIDL 擁有的記憶體建立指標。不建議使用,因為
很容易不小心產生使用釋放後的錯誤。多數觀看類型提供
FromExternal
工廠函式,明確地將指標借用到
並非由 FIDL 執行階段管理
如何使用外部物件建立 ObjectView
fidl::ObjectView<T>::FromExternal
:
fidl::StringView str("hello");
// |object_view| is a view that borrows the string view.
// Destroying |str| will invalidate |object_view|.
fidl::ObjectView object_view = fidl::ObjectView<fidl::StringView>::FromExternal(&str);
// |object_view| may be dereferenced to access the pointee.
ASSERT_EQ(object_view->begin(), str.begin());
如要使用以下方式從外部集合建立 VectorView
:
fidl::VectorView<T>::FromExternal
:
std::vector<uint32_t> vec = {1, 2, 3, 4};
// |vv| is a view that borrows the vector contents of |vec|.
// Destroying the contents in |vec| will invalidate |vv|.
fidl::VectorView<uint32_t> vv = fidl::VectorView<uint32_t>::FromExternal(vec);
ASSERT_EQ(vv.count(), 4UL);
如要使用外部緩衝區建立 StringView
,請按照下列步驟操作:
fidl::StringView::FromExternal
:
std::string string = "hello";
// |sv| is a view that borrows the string contents of |string|.
// Destroying the contents in |string| will invalidate |sv|.
fidl::StringView sv = fidl::StringView::FromExternal(string);
ASSERT_EQ(sv.size(), 5UL);
也可直接透過字串常值建立 StringView
,無需使用
FromExternal
。這是安全的,因為字串常值
靜態生命週期。
fidl::StringView sv1 = "hello world";
fidl::StringView sv2("Hello");
ASSERT_EQ(sv1.size(), 11UL);
ASSERT_EQ(sv2.size(), 5UL);
若要製作線會聯集借給外部儲存的成員,請傳送
ObjectView
會將成員參照對應的聯集工廠函式:
fidl::StringView sv = "hello world";
fuchsia_examples::wire::JsonValue val = fuchsia_examples::wire::JsonValue::WithStringValue(
fidl::ObjectView<fidl::StringView>::FromExternal(&sv));
ASSERT_TRUE(val.is_string_value());
fidl::WireTableFrame<SomeTable>
線表儲存參照,
負責追蹤欄位中繼資料如何建立電線表
借用外部框架,將 ObjectView
傳遞至 ExternalBuilder
。
以下是設定頁框中欄位的範例:
fidl::WireTableFrame<fuchsia_examples::wire::User> frame;
// Construct a table creating a builder borrowing the |frame|.
auto builder = fuchsia_examples::wire::User::ExternalBuilder(
fidl::ObjectView<fidl::WireTableFrame<fuchsia_examples::wire::User>>::FromExternal(&frame));
// Small values <= 4 bytes are inlined inside the frame of the table.
builder.age(30);
// The builder is turned into an actual instance by calling |Build|.
auto user = builder.Build();
ASSERT_FALSE(user.IsEmpty());
ASSERT_EQ(user.age(), 30);
以下範例說明如何設定從影格外儲存的欄位:
fidl::WireTableFrame<fuchsia_examples::wire::User> frame;
// Construct a table creating a builder borrowing the |frame|.
auto builder = fuchsia_examples::wire::User::ExternalBuilder(
fidl::ObjectView<fidl::WireTableFrame<fuchsia_examples::wire::User>>::FromExternal(&frame));
// Larger values > 4 bytes are still stored out of line, i.e. outside the
// frame of the table. One needs to make an |ObjectView| pointing to larger
// fields separately, using an arena or with unsafe borrowing here.
fidl::StringView str("hello");
fidl::ObjectView object_view = fidl::ObjectView<fidl::StringView>::FromExternal(&str);
builder.name(object_view);
// The builder is turned into an actual instance by calling |Build|.
auto user = builder.Build();
ASSERT_FALSE(user.IsEmpty());
ASSERT_TRUE(user.has_name());
ASSERT_EQ(user.name().get(), "hello");