QList官方幫助文檔-詳細介紹部分(個人翻譯)

Qt通用容器類QList<T>,使用列表存儲條目,支持基於索引的快速訪問、插入及刪除。
QList<T>、QLinkedList<T>和QVector<T>三者的APIs和功能幾乎一樣。經常相互替換,但性能側重點有區別。以下是使用概述。
默認第一選擇QVector,通常QVector<T>性能優於QList<T>。這是由於QVector<T>是在內存中按順序地存儲條目,而QList<T>是在堆上爲他的條目分配內存
(當sizeof(T)<=sizeof(void*),且T被聲明爲Q_MOVABLE_TYPE,或Q_PRIMITIVE_TYPE(需要使用Q_DECLARE_TYPEINFO)時,除外)
參考Pros and Cons of Using QList的解釋

然而,QList的使用,貫穿於整個Qt APIs,通常當做傳遞參數和返回值。用QList與這些APIs交互更方便。
QLinkedList使用迭代器訪問,而不是索引,能保證每次插入所耗時間不變,是貨真價實的鏈式列表。

注意:QVector和QVarLengthArray都兼容C風格數組,而Qlist不支持。對於必須使用C API的應用,瞭解這點,或許會很重要。
注意:只要條目還在容器中,QLinkedList上的迭代器,以及內存分配在堆上QList的引用,將一直有效。

如果sizeof(T)<=sizeof(void*),且T被申明爲一個Q_MOVABLE_TYPE或Q_PRIMITIVE_TYPE(需使用Q_DECLARE_TYPEINFO),本質上,QList<T>與array<T>等同。
QList<T>可理解爲一個T*的數組(Array),而條目本身被分配於堆(heap)上。
數組(array)的特點是特快的插入和基於索引的訪問。由於內存數組的兩端預先分配了內存,QList的prepend()與append()運行也非常快。(詳見Algorithmic Complexity)

需要注意的是,非以上情況,每一次追加或插入一個新條目,都需要在堆上重新分配條目內存。QVector則是一個單獨連續的堆內存上分配多個條目內存。若需做大量追加和插入,QVector更合適。

另一點需要注意的是,列表生命週期中,其內在數組只會一直變大,不收縮。內在數組可被析構函數和賦值運算重新分配(一個列表被賦值爲另一個列表)。

下例分別是一個存儲整數的列表(QList)和一個存儲日期(QDate)的列表(QList)
QList<int> integerList;
QList<QDate> dateList;

Qt有個類QStringList,繼承自QList<QString>,並增加了一些便捷的函數。例如:QStringList::join()和QStringList::filter()以及
QString::split()(用於從多個字符串創建QStringLists)


QList是用於存儲多個條目的列表容器,默認構造函數只會創建一個空列表,但可用初始值列表初始化一個內含條目的列表。
QList<QString> list = { "one", "two", "three" };

QList不僅提供insert(), replace(), removeAt(), move(), and swap()這幾個函數用於條目的基本增、移動、刪,
還提供更便捷的函數append()、operator<<()、operator+=()、prepend()、removeFirst()和removeLast()。
如下所示,operator<<()能便捷地添加多個元素到列表中。
 list << "four" << "five";

與C++數組一致,QList使用零基索引。用operator[]()訪問指定索引位置的條目。
非常量列表(non-const lists),operator[]()返回條目索引,可用於賦值運算的左邊
  if (list[0] == "Bob")
      list[0] = "Robert";
      
由於QList是由一組指向大於指針類型的數據類型(或不可移動)數據類型的指針構成的數組。所以訪問與賦值運算需要 時間(constant time)。
對於只讀訪問,建議用替代函數爲at()

  for (int i = 0; i < list.size(); ++i) {
      if (list.at(i) == "Jane")
          cout << "Found Jane at position " << i << endl;
  }

at()運算速度高於operator[](), 因爲他不會引起深拷貝。
從列表中提出(讀取出元素後,並將它從列表中刪除)一個條目,然後用它做點什麼,是很常見的需求。
爲滿足該類需求,QList提供了takeAt(), takeFirst(),和takeLast()函數。
下例爲,用循環刪除列表中所有條目,一次只刪一個,並用delete釋放條目對象:

  QList<QWidget *> list;
  ...
  while (!list.isEmpty())
      delete list.takeFirst();
      
QList在它的內部緩存中提前預分配出了額外的空間,從而使列表兩端快速地增長。所以列表的兩端插入和刪除條目非常快(多數情況都是constant time)。
用indexOf() 或lastIndexOf()在列表中找出所有的特定值。前者從給定索引向前搜索,後者向後搜索。若找到特定值,兩者都返回對應條目索引;否則,返回-1。
例:
  int i = list.indexOf("Jane");
  if (i != -1)
      cout << "First occurrence of Jane is at position " << i << endl;

用contains()檢查列表中是含有特定值。用count()獲取列表中特定值的個數。用replace()替換所有特定值爲另一個值。
QList的值類型,必須是可被分配的數據類型。常用的大多數數據類型都包含在內,但是編譯器不會允許你將QWidget按值去存儲,取而代之的是,存儲QWidget *。
QList一些函數有特殊的使用條件,例如:indexof()和lastIndexOf() 需要數據類型支持運算符operator==()。
這些特殊的條件,分別記錄在單條函數說明中
與其他容器類一樣,QList支持Java-style迭代器(QListIterator和QMutableListIterator)和STL-style迭代器(QList::const_iterator和 QList::iterator)。
單它們極少被用到。這是因爲QList支持索引訪問,速度與迭代器相當。

QList不支持用自己的條目值去做做插入、前追加,後追加或替換運算。這樣的錯誤使用,會導致應用異常中止,並得到一個錯誤信息。

爲儘可能使QList高效,它的成員函數在使用前,並不驗證輸入參數的合法性。
除了isEmpty(),其他成員函數都假設列表非空。成員函數使用的索引,通常是假設它是在有效範圍內的。
編譯時,若定義了QT_NO_DEBUG,那麼,及時QList成員函數失敗,錯誤也不會被發現。
若沒定義了QT_NO_DEBUG,失敗錯誤會被偵查出來,並用Q_ASSERT()或Q_ASSERT_X()提示一箇中肯的錯誤原因。
爲避免列表爲空時成員函數調用失敗的這些錯誤,調用其他成員函數前,先調用isEmpty()檢查下列表是否爲空。
若不能確定傳遞的索引是否在有效範圍內,檢查該索引是否小於size()並且大於0即可。


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章