開始使用

本節將顯示使用中乾擾性容器的簡單範例,並花一些時間討論一些基本作業的細節。本指南的後續章節會進一步說明這些概念及其他許多概念,但本節將提供以下基本示範:

  1. 指標類型,以及如何運用指標控管物件的生命週期。
  2. 可納入的「mix-ins」部分,以及如何運用這類元素允許物件存在容器中。
  3. 如何疊代 fbl:: 幹擾容器中的元素。
  4. 如何從 fbl:: 侵入式容器移除元素
  5. fbl:: 侵入式容器設定建構依附元件

簡單範例

讓我們從簡單的範例開始著手。在這個範例中,系統會定義一個物件,並存在於二連串連結清單中,並使用 std::unique_ptr<> 追蹤。這些物件的清單如下:

  1. 已填入
  2. 疊代以輸出物件子集
  3. 疊代以移除部分物件
  4. 已明確清理
#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(),因此捨棄所有參照。

「原始」指標沒有特殊的擁有權語義,代表使用者完全負責確保物件在容器中保持有效狀態,且在從容器移除或清除物件時,可適當清理物件。

可列出/內含的混合式課程

如果物件必須將下一個/上一個指標儲存在其他位置,則這個節點狀態在哪裡?清單如何找到這個節點?實際上有幾種方法可以控制這種行為,但本範例示範最簡單的方法。這是從 DoublyLinkedListListable 混合輔助程式衍生而來。就像清單本身一樣,您需要透過第一個範本引數,將物件類型及指標類型告知混用項目。這些類型必須符合指派給清單定義的類型。根據預設,清單將會尋找 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 檔案的 depspublic_deps 區段。這個參考資料包含在 deps 區段中,以便在使用者編寫可執行的作業時,或只在程式庫的私人部分使用 fbl。如要在使用者程式庫的公開標頭中的任何位置使用 fbl,請改用 public_deps