C++ STL iterator迭代器操作詳解


前言

首先我們知道在容器中,迭代器分爲:

  • iterator
  • const_iterator
  • reverse_iterator
  • const_reverse_iterator

官方文檔對迭代器實際上可以分爲這幾類:

  • Input iterator 輸入迭代器
  • Output iterator 輸出迭代器
  • Forward iterator 正向迭代器
  • Bidirectional iterator 雙向迭代器
  • Random-access iterator 隨機存取迭代器

注意每個容器的迭代器類型不一定相同,如vector的迭代器就是隨機存取迭代器,而list則是雙向迭代器
具體的可以在www.cplusplus.com/reference/iterator/index.html
進行查閱


一.Functions(函數)操作

  • advance
  • distance
  • prev
  • next
void test1()
{
    //advance
    list<int> mylist{1, 2, 3, 4, 5, 6};
    list<int>::iterator it = mylist.begin();
    //it +=5;//ERROR!iterator do not support operator +=
    it++;
    it++;
    it++;
    it++;
    cout << *it << endl;
    it = mylist.begin();
    advance(it, 2);
    cout << *it << endl;

    //distance
    cout << "distance:" << distance(mylist.begin(), it) << endl;

    //prev
    it = mylist.end();
    cout << "The last element:" << *(--it) << endl;
    cout << "Now *it = " << *it << endl;
    cout << "如果並不想要迭代器變化,只想輸出迭代器指向前一個元素的迭代器:" << endl;
    cout << *prev(mylist.end()) << endl;
    //next
    cout << *next(mylist.begin()) << endl;

    cout << "next還可以有類似advance的用法,但是也並不會改變原來的迭代器指向" << endl;
    cout << *next(mylist.begin(), 3) << endl;

    cout << "for_each + next" << endl;
    for_each(mylist.begin(), next(mylist.begin(), 3), [](int x) { cout << x << endl; });
}

二.Iterator generators

  • back_inserter:不斷往後插入元素
  • front_inserter:不斷往前插入元素
  • inserter:需要確定容器與插入的位置

這些操作可以用來針對哪些沒有insert函數的容器使用

//例題:要在一個容器中間插入另外一個容器的元素
void test2()
{
    list<int> mylist{1, 2, 3, 4, 5};
    list<int> newlist{10, 20, 30, 40};
    auto it = newlist.begin();
    std::advance(it, 2);
    std::copy(mylist.begin(), mylist.end(), inserter(newlist, it));

    for (auto &e : newlist)
        cout << e << endl;
}

//back_inserter front_inserter
void test3()
{
    list<int> mylist{1, 2, 3, 4, 5};
    list<int> newlist;
    //不要用.end()來執行copy操作,因爲.end()返回的並不屬於插入迭代器,並不能對newlist進行擴容,所以會發生錯誤
    // std::copy(mylist.begin(), mylist.end(), newlist.end());

    //back_inserter
    std::copy(mylist.begin(), mylist.end(), std::back_inserter(newlist));

    for (auto &e : newlist)
        cout << e << endl;
    cout << "-----------------------------" << endl;

    //front_inserter 注意這裏插入的順序是相反的
    list<int> mylist2{6, 7, 8, 9};
    std::copy(mylist.begin(), mylist.end(), std::front_inserter(mylist2));

    for (auto &e : mylist2)
        cout << e << endl;
}

三.predefined iterator

1.insert_iterator、back_insert_iterator、front_insert_iterator

  • insert_iterator:容器中必須有insert操作
  • back_insert_iterator:容器中必須有push_back操作
  • front_insert_iterator:容器中必須有push_front操作
    y67
void test4()
{
    list<int> mylist{1, 2, 3, 4, 5};
    list<int> newlist;

    //insert_iterator
    std::insert_iterator<list<int>> insert_it(newlist, newlist.begin());
    std::copy(mylist.begin(), mylist.end(), insert_it);

    for (auto &e : newlist)
        cout << e << endl;
    cout << "--------------------------" << endl;

    vector<int> vec{1, 2, 3};
    vector<int> newvec{10, 20, 30};
    std::back_insert_iterator<vector<int>> back_it(newvec);
    std::copy(vec.begin(), vec.end(), back_it); //如果換成vec.end()會報錯
    for (auto &e : newvec)
        cout << e << endl;
    cout << "----------------------------------" << endl;

    /*
    //ERROR!vector中沒有push_front操作 
    std::front_insert_iterator<vector<int>> front_it(newvec);
    std::copy(vec.begin(), vec.end(), front_it);
    for (auto& e: newvec)
        cout << e << endl;
    */
}

2.reverse_iterator

這裏需要特別注意的是:reverse_iterator 相比 iterator 會向左邊有1個單位的offset(偏移)

因爲STL容器中的函數,如erase, insert函數等等只能操作正向迭代器,不能操作反向迭代器,所以反向迭代器中便有了base函數將其轉換爲正向迭代器,但是注意有偏移

注意:使用base函數之後,指針右移一位,再轉換爲正向迭代器

/*
?      1       2       3       4       5       ?
    vec.begin()                              vec.end()
                                      rbeg
rend



*/

void test5()
{
    vector<int> vec{1, 2, 3, 4, 5};

    std::reverse_iterator<vector<int>::iterator> rbeg(vec.end());
    std::reverse_iterator<vector<int>::iterator> rend(vec.begin());

    cout << *rbeg << endl;
    cout << *rbeg.base() << endl;
    cout << *rend << endl;
    cout << *rend.base() << endl;
    cout << "-------用逆向迭代器刪除數組中的3------------" << endl;
    std::reverse_iterator<vector<int>::iterator> rit = find(vec.rbegin(), vec.rend(), 3);
    std::reverse_iterator<vector<int>::iterator> rit2 = rit;
    cout << *rit << endl;
    rit++;
    cout << *rit << endl;
    rit++;
    cout << *rit << endl;
    cout << "由此可見rit 的本質仍然是反向迭代器" << endl;
    // vec.erase(rit2);
    // vec.erase(rit2.base());
    vec.erase((++rit2).base());
    cout << "----------------print---------------------------" << endl;
    for (auto &e : vec)
        cout << e << endl;
}

void test6()
{
    vector<int> vec{1, 2, 3, 4, 5};
    std::reverse_iterator<vector<int>::iterator> rbeg(vec.end());
    std::reverse_iterator<vector<int>::iterator> rend(vec.begin());
    cout << "迭代器的類型-----------------------------" << endl;
    vector<int>::reverse_iterator rit = rbeg;
    std::reverse_iterator<vector<int>::iterator> rit2 = rbeg;
    cout << *rit << endl;
    cout << *rit2 << endl;
    cout << "正序打印---------------------------------" << endl;
    for (vector<int>::iterator it = rend.base(); it != rbeg.base(); it++)
        cout << *it << endl;
    cout << "逆序打印---------------------------------" << endl;
    while (rbeg != rend)
        cout << *rbeg++ << endl;
}

3.istream_iterator ostream_iterator

cin輸入的次數取決於istream_it迭代器的移動次數
ostream_it會自動輸出移動

void test7()
{
    std::istream_iterator<double> istream_it(std::cin);
    std::istream_iterator<double> eof;
    vector<double> vec;
    vec.push_back(*istream_it);
    istream_it++;
    vec.push_back(*istream_it);
    istream_it++;
    vec.push_back(*istream_it);
    istream_it++;

    for (auto &e : vec)
        cout << e << endl;
}

void test8(){
    vector<int> vec{1,2,3,4,5};
    std::ostream_iterator<int> ostream_it(cout," ");
    *ostream_it = 1;
    *ostream_it = 2;
    *ostream_it = 3;
    cout << endl;
    cout << "----------------------------" << endl;
    std::copy(vec.begin(), vec.end(), ostream_it);
}

4.std::move 與 std::move_iterator

移動語義 move 與 移動迭代器
注意:當src元素中move過去之後就不能再使用了,儘管還能夠再次輸出,但是程序有安全隱患。

void test9(){
    vector<int> src{1,2,3,4};
    vector<int> dest{5,6,7};
    typedef vector<int>::iterator Iter;//定義底層的基本迭代器
    std::copy(std::move_iterator<Iter>(src.begin()), std::move_iterator<Iter>(src.end()), std::back_inserter(dest));
    // std::move(src.begin(), src.end(), std::back_inserter(dest));
    cout << "src:" << endl;
    for (auto& e: src)
        cout << e << " ";
    cout << endl;
    cout << "dest:" << endl;
    for (auto& e: dest)
        cout << e << " ";
    cout << endl; 
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章