【Qt】C++中的循環遍歷

介紹
     本文主要討論C++中常見的幾種循環遍歷操作的語法:基於迭代器、基於Qt庫中的foreach關鍵字、基於C++11新增的for循環語句。


基於迭代器的遍歷
在C++容器中經常需要進行遍歷操作,在C++11之前一般使用下面這種方式——基於迭代器的遍歷:
    QList<QString> list {"a", "b", "c", "d"};
    QList<QString>::const_iterator citer = list.cbegin();
    for (; citer != list.cend(); ++citer)
        qDebug() << (*citer);
獲取容器的開始迭代器,然後輸入當前迭代器指向的值,將迭代器指向下一個位置,依次下去直到迭代器到達容器尾端迭代器終止遍歷操作。這種方式提供了可變迭代器和常量迭代器,前者可以在移動遍歷過程中修改容器內容,後者則是隻讀式的遍歷。迭代器作爲一種接口,可以很方便的提供給C++中其他標準庫調用,如排序、插入、刪除、輸入輸出等。

但作爲一般的遍歷操作,其存在一些不足,首先就是代碼冗長,其次就是:我只是想遍歷容器每個元素,至於容器內元素的位置我並不關心,可是上面操作你必須小心的爲迭代器賦值和移動,一旦失誤導致迭代器超出容器的迭代器範圍會導致未知錯誤。

foreach關鍵字
在 Qt 核心庫中提供了一個 foreach 關鍵字,其實就是一個宏,通過預處理器實現,讓我們可以很方便的進行一般的遍歷操作:
    QList<QString> list {"a", "b", "c", "d"};
    foreach (QString s, list)
        qDebug() << s;
這比 Qt 庫中提供的類java的迭代器代碼還要少一些:
    QListIterator<QString> iter(list);
    while(iter.hasNext())
        qDebug() << iter.next();
在Qt程序中使用 foreach 確實非常的方便簡潔,但使用時也需要注意一點:foreach 遍歷的是原始容器的副本(通過隱式共享實現,所以非常快)所以通過非const的引用修改容器對原始容器不會產生效果,不過你也無法使用非const的常量引用來修改,因爲foreach內部將容器標識爲了 const(有興趣可以看下面的代碼)。
#define Q_FOREACH(variable, container)                                \
    for (QForeachContainer<__typeof__(container)> _container_(container); \
    !_container_.brk && _container_.i != _container_.e;              \
    __extension__  ({ ++_container_.brk; ++_container_.i; }))                       \
    for (variable = *_container_.i;; __extension__ ({--_container_.brk; break;}))                                  
    
template <typename T>
    class QForeachContainer {
    public:
        inline QForeachContainer(const T& t) : c(t), brk(0), i(c.begin()), e(c.end()) { }
        const T c;         // 將容器標識爲 const 不可修改
        int brk;
        typename T::const_iterator i, e;
    };
foreach 這種方式的優點就是:簡單快捷,但不適合需要修改原始容器的場合。

C++11新曾的for循環語句
基於範圍的for循環,繼承了Qt庫中foreach的優點,同時避免了其不足——可以修改原始容器,重寫上面例子:
    for (QString s : list)
        qDebug() << s;
如果變量類型較長,可以使用auto來讓編譯器自動推斷,如下:
    for (auto s : list)
        qDebug() << s;
通過非const變量引用修改原始容器:
for (auto &s : list)
    s = "x";
基於範圍的for循環配合C++11中的auto關鍵字,可以大幅節省需要書寫的代碼量,同時也非常的簡潔方便。
要說不足的話就是編譯器的支持不足(C++11規範新增的),不過最新版的各種C++編譯器都已經支持了,如果你的編譯器支持的話,下次就記得用哦~
發佈了50 篇原創文章 · 獲贊 27 · 訪問量 25萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章