本節將顯示使用中乾擾性容器的簡單範例,並花一些時間討論一些基本作業的細節。本指南的後續章節會進一步說明這些概念及其他許多概念,但本節將提供以下基本示範:
- 指標類型,以及如何運用指標控管物件的生命週期。
- 可納入的「mix-ins」部分,以及如何運用這類元素允許物件存在容器中。
- 如何疊代
fbl::
幹擾容器中的元素。 - 如何從
fbl::
侵入式容器移除元素。 - 從
fbl::
侵入式容器設定建構依附元件。
簡單範例
讓我們從簡單的範例開始著手。在這個範例中,系統會定義一個物件,並存在於二連串連結清單中,並使用 std::unique_ptr<>
追蹤。這些物件的清單如下:
- 已填入
- 疊代以輸出物件子集
- 疊代以移除部分物件
- 已明確清理
#include <stdint.h>
#include <fbl/intrusive_double_list.h>
// An object that holds an immutable int and can exist on a doubly linked list
// managed using a std::unique_ptr
class MyObject : public fbl::DoublyLinkedListable<std::unique_ptr<MyObject>> {
public:
explicit MyObject(int val) : val_(val) {}
int val() const { return val_; }
private:
const int val_;
};
extern void TakeThisObjectFromMe(std::unique_ptr<MyObject>);
void DoThings() {
fbl::DoublyLinkedList<std::unique_ptr<MyObject>> list;
// Add 100 random integers to our list.
for (uint32_t i = 0; i < 100; ++i) {
list.push_back(std::make_unique<MyObject>(rand()));
}
// print out any members of the list that are even
for (const auto& obj : list) {
if (!(obj.val() % 2)) {
printf("Even Object %d\n", obj.val());
}
}
// Remove any objects that are divisible by 7 and give them to someone else.
for (auto iter = list.begin(); iter != list.end(); ) {
auto consider = iter++;
if (!(consider->val() % 7)) {
TakeThisObjectFromMe(list.erase(consider));
}
}
// Destroy the rest of the object by forcing the list to release its unique
// references to the objects. We could also simply let the list leave the
// scope of the function, which would do the same.
list.clear();
}
指標類型
這裡首先需要注意的其中一項,而 std::
容器和 fbl::
容器間的重要差異在於 fbl::
容器一律會使用指標追蹤物件。具體而言,系統會使用一組明確支援的指標類型追蹤這些錯誤。定義 fbl::
清單的類型時,會將清單定義為物件類型的特定指標類型清單。在此範例中,選擇 std::unique_ptr<>
代表物件的不重複參照可能會保存在本機或保留在清單中,但不能同時保存。fbl::
容器目前允許使用 3 種不同的指標類型:
T*
:沒有代管 RAII 語意的原始指標類型。std::unique_ptr<T, Deleter>
:標準的專屬指標類型,可使用自訂刪除器或預設刪除工具。fbl::RefPtr<T>
:fbl::
幹擾的參考指標。基本上,fbl::
的std::shared_ptr<T>
幹擾版本。
您必須透過容器類型的第一個範本引數,告知所有容器保留的物件類型,以及使用何種指標來管理生命週期。使用代管指標類型時,將物件新增至容器時,容器一律會取得參照的擁有權,並在物件從容器中移除時授予該參照的擁有權。這項規則的例外狀況是 clear()
,因此捨棄所有參照。
「原始」指標沒有特殊的擁有權語義,代表使用者完全負責確保物件在容器中保持有效狀態,且在從容器移除或清除物件時,可適當清理物件。
可列出/內含的混合式課程
如果物件必須將下一個/上一個指標儲存在其他位置,則這個節點狀態在哪裡?清單如何找到這個節點?實際上有幾種方法可以控制這種行為,但本範例示範最簡單的方法。這是從 DoublyLinkedList
的 Listable
混合輔助程式衍生而來。就像清單本身一樣,您需要透過第一個範本引數,將物件類型及指標類型告知混用項目。這些類型必須符合指派給清單定義的類型。根據預設,清單將會尋找 Listable
混合的執行個體,該執行個體會從該物件衍生,以找出其用於簿記的節點狀態。上述所有作業都會在編譯時間發生,在物件中找出節點狀態時,不會衍生執行階段負擔。
疊代
fbl::
容器支援以範圍為基礎的迴圈疊代,以及更傳統的 start()/end() 疊代樣式。與 std::
容器一樣,使用以範圍為基礎進行列舉時,會傳回物件的 l 值參照。請務必記得在 for 迴圈中說出 auto&
或 const auto&
(甚至是 MyObject&
),而不是只說 auto
,以免意外觸發物件的複製建構函式。
fbl::
容器疊代器也支援 ++
運算子的標準預先修正和後置格式,您可以看到這些格式,可讓您在疊代時從清單中選擇性移除元素。這個範例使用修正後表單,讓 consider
成為可能選擇移除的元素,而 iter
則代表清單中需要考慮的下一個元素。
疊代器就像在清單中其他元素上的非代管指標一樣。您可以使用 ->
運算子或 (*iter).val()
樣式,以所有標準方式存取基礎物件。您甚至可以說出 &(*iter)
,將原始指標擷取至物件。由於疊代器是物件的原始指標,因此應謹慎處理。我們不建議您將這類金鑰儲存任意時間,特別是使用新型代管指標控管物件的生命週期時。
移除元素
在這個範例中,在移除元素時,這些元素會使用疊代器清除。清除作業的結果會是清單所用指標類型的 R 值參照。該參照可能已取回並保存在本機指標執行個體中,但在這種情況下,該參照會直接移到某些外部函式的呼叫中,將物件的專屬擁有權從清單轉移至程序中的外部函式。
clear()
是移除容器中的元素另一種方法,但會捨棄所有元素參照,也可能會刪除在程序中指向的物件。
設定建構依附元件
如要使用 fbl::
容器,使用者必須同時加入要使用的容器適用的標頭檔案,並在專案的 BUILD.gn
檔案中納入 fbl
程式庫的依附元件。
各個容器類型的必要檔案包括:
容器類型 | 納入聲明 |
---|---|
fbl::SinglyLinkedList<> |
#include <fbl/intrusive_single_list.h> |
fbl::DoublyLinkedList<> |
#include <fbl/intrusive_double_list.h> |
fbl::WAVLTree<> |
#include <fbl/intrusive_wavl_tree.h> |
fbl::HashTable<> |
#include <fbl/intrusive_hash_table.h> |
使用者也必須將程式庫 //zircon/system/ulib/fbl
新增至專案 BUILD.gn
檔案的 deps
或 public_deps
區段。這個參考資料包含在 deps
區段中,以便在使用者編寫可執行的作業時,或只在程式庫的私人部分使用 fbl
。如要在使用者程式庫的公開標頭中的任何位置使用 fbl
,請改用 public_deps
。