1. 程式人生 > >叠代器精彩演繹,失效分期及彌補、實戰

叠代器精彩演繹,失效分期及彌補、實戰

寫法 而不是 內存釋放 ack inf 對象 string類型 跳出循環 逆向

一、叠代器簡介

叠代器是一種遍歷容器內元素的數據類型。這種數據類型感覺有點像指針。

string,vector,[],很少用[],更通用的方式就是用叠代器。

通過叠代器,我們可以讀容器中的元素值,讀string中的每個字符,還可以修改某個叠代器所指向的元素值。

叠代器支持++,--自增,自減操作,相關list/map容器

二、容器的叠代器類型

vector<int> iv(100,200,300);
vector<int>::iterator iter; // 定義叠代器,也必須是vector<int>

三、叠代器的begin()/end(),反向叠代器rbegin()/rend()操作

begin()/end()用來返回叠代類型,rbegin()/rend()返回叠代類型

(1)begin()返回一個叠代器類型

iter = iv.begin();// 如果容器中有元素,則begin返回的叠代器,指向容器中的第一個元素。 即iter指向了iv[0]

(2)end():返回叠代器類型

iter = iv.end(); // end返回的叠代器指向的並不是末端元素,而是末端元素的後邊

(3)如果一個容器為空,則begin()/end()返回的叠代器相同

vector<int> iv2;
vector<int>::iterator iterbegin = iv2.begin();
vector
<int>::iterator iterend = iv2.end(); if(iterbegin == iterend) { cout << “容器iv2為空” << endl; }

(4)傳統叠代器的寫法

vector<int> iv(100,200,300);
for(vector<int>::iterator iter = iv.begin();iter != iv.end(); iter++)
{
    cout << *iter << endl; // 依次打印100,200,300
}

(5)反向叠代器

反向叠代器:從後往前遍歷容器中的元素

反向叠代器(逆向叠代器),用的rbegin(),rend()

rbegin()返回一個反向叠代器,指向反向叠代器的第一個元素

rend()返回一個反向叠代器,指向反向叠代器的最後一個元素的下一個位置

vector<int> iv(100,200,300);
for(vector<int>::reverse_iterator riter = iv.rbegin(); riter != iv.rend(); riter++)
{
    cout << *riter << endl; // 依次打印300,200,100
}

四、叠代器運算符

(1)*iter:返回叠代器iter所指向元素的引用。必須保證這個叠代器指向的是有效的容器元素,不能指向end(),因為end()是末端後面的元素,即end()是指向一個不存在的元素。

vector<int> iv(100,200,300);
//vector<int>::iterator iter = iv.end(); // 存在問題
vector<int>::iterator iter = iv.begin();
cout << *iter << endl;

(2)++iter,iter++:讓叠代器指向容器的下一個元素;已經指向end()時候,不能再自加,自減。

//vector<int>::iterator iter = iv.end(); // 存在問題
vector<int>::iterator iter = iv.begin();
iter++;
cout << *iter << endl;

(3)--iter,iter--:讓叠代器指向容器中的上一個元素。指向開頭元素,不能再--

//vector<int>::iterator iter = iv.begin(); // 存在問題
vector<int>::iterator iter = iv.end();
iter--;
cout << *iter << endl;

(4)iter1 == iter2; iter1 != iter2 判斷兩個叠代器是否相等。

如果兩個叠代器指向的是同一個元素,就相等,否則就不等。

(5)如何引用結構中的成員

struct student
{
int num;
};

vector<student> sv;
student mystu;
mystu.num = 100;
sv.push_back(mystu); // 把對象mystu賦值到了sv容器中。

 
vector<student>::iterator iter; // 確保叠代器指向有效的對象
iter = sv.begin(); // 指向第一個元素
cout << (*iter).num << endl; 
cout << iter->num << endl;

五、const_iterator叠代器,const:常量

const_iterator叠代去,表示值不能改變的意思,這裏的值不能改變表示這個叠代器指向的元素的值不能改變,而不是表示這個叠代器本身不能改變,即叠代器本身是可以不斷指向下一個元素;只能從容器中讀元素,不能通過這個叠代器改寫容器中的元素,感覺起來更像常量指針。

const vector<int> iv = {100,200,300};
vector<int>::const_iterator iter;
for(iter = iv.begin(); iter != iv.end(); iter++)
{
    //*iter = 4; // 出錯,不可修改
    cout << *iter << endl;
}

(1)cbegin()/cend()操作

C++11引入的兩個新函數,跟begin,end類似;cbegin,cend,返回的都是常量叠代器

for(auto iter = iv.cbegin(); iter != iv.cend(); iter++)
{
    //*iter = 4; // 報錯,不能給常量賦值,這說明cbegin返回的是常量叠代器。
    cout << *iter << endl;
}

六、叠代器失效

vector<int> vecvalue{1,2,3,4,5};

for(auto vecitem : vecvalue)
{
    //vecvalue.push_back(444); // 報錯,顯示結果混亂
    cout << vecitem << endl;
}

for(auto beg = vecvalue.begin(); beg != vecvalue.end(); beg++)
{
    //vecvalue.push_back(444); // 報錯,崩潰
    cout << *beg << endl;
}

在操作叠代器的過程中,使用叠代器這種循環體,千萬不要改變vector容器的容量。即不要增加或刪除vector容器中的容量。

向容器中增加元素或刪除元素,這些操作可能會使指向容器元素的指針,引用,叠代器失效,失效表示不能再代表任何容器中的元素。一旦使用失效的東西,就等於犯了嚴重的程序錯誤,很多情況下,程序會直接崩潰。

for(auto beg = vecvalue.begin(); beg != vecvalue.end(); beg++)
{
    vecvalue.push_back(444);
    break; // 插入新元素直接跳出
}

for(auto beg = vecvalue.begin(); beg != vecvalue.end(); beg++)
{
    cout << *beg <<endl;
}

(1)災難程序1

vector<int> vecvalue{1,2,3,4,5};
auto beg = vecvalue.begin();
auto end = vecvalue.end();

while(beg != end)
{
    cout << *beg << endl;
    // 加入想往begin這個位置插入新值,可以用insert
    vecvalue.insert(beg,80); //插入新值,第一個參數為插入位置,第二個參數為插入值。
    // 這個值的插入,會使叠代器失效。比如begin,end失效
    // 具體哪個叠代器失效,取決於vector內部的實現原理。
    // 最明智的做法就是立即break跳出循環,否則程序會崩潰。
    break;
    beg++; // 不要忘記,並且放在循環末尾
}

beg = vecvalue.begin();
end = vecvalue.end();

while(beg != end)
{
    cout << *beg << endl;
    beg++; // 不要忘記,並且放在循環末尾
}
// 叠代器插入防止叠代器失效
vector<int> vecvalue{1,2,3,4,5};
auto beg = vecvalue.begin();
auto end = vecvalue.end();
int icount = 0;

while(beg != vecvalue.end()) // 每次更新end防止end失效
{
    beg = vecvalue.insert(beg,icount+80);
    icount++;
    if(icount>10) break;
    ++beg;
}

// 遍歷叠代器裏面的數據
beg = vecvalue.begin();
end = vecvalue.end();
while(beg != end)
{
    cout << *beg << endl;
    beg++; // 不要忘記,並且放在循環末尾
}

(2)災難程序2 – 容器的釋放問題

vector<int> iv = {100,200,300};
//
for(auto iter = iv.begin();iter != iv.end();iter++)
{
    // erase函數,移除iter位置上的元素,返回下一個元素位置
    iv.erase(iter);  // 存在問題,直接崩潰
}

// 穩定版容器釋放
vector<int> iter = iv.begin();
while(iter != iv.end())
{
    iter = iv.erase(iter);
}

// 更簡單的釋放
while(!iv.empty())
{
    auto iter = iv.begin();// 因為不為空,所以返回的begin()是沒問題
    iv.erase(iter); // 刪除該位置上的元素
}

七、範例演示

(1)用叠代器編譯string類型數據

string str(“I Love China”);
for(auto iter = str.begin();iter != str.end();++iter)
{
    *iter = toupper(*iter);
}
cout << str << endl;

(2)vector容器常用操作及內存釋放

叠代器實戰例子

// ServerName = 1區 // 表示服務器名稱
// ServeID = 100000 // 服務器ID
struct conf
{
    char itemname[40];  // 項目名
    itemContext[100];    // 項目內容   
};

// 根據項目名查詢項目內容
char *getinfo(vector<conf *> &conflict,const char *pitem)
{
    for(auto pos = conflict.begin(); pos != conflict.end(); ++pos)
    {
       if(_strcmp((*pos)->itemname,pitem) == 0) 
       {
            return (*pos)->itemcontext;
       }
    }
    return nullptr;
}

int main()
{
    conf *pconf1 = new conf;
    strcpy_s(pconf1->itemname,sizeof(pconf1->itemname),”ServerName”);
    strcpy_s(pconf1->itemcontext,sizeof(pconf1->itemcontext),”1區”);

    conf *pconf2 = new conf;
    strcpy_s(pconf2->itemname,sizeof(pconf2->itemname),” ServeID”);
    strcpy_s(pconf2->itemcontext,sizeof(pconf2-> itemcontext),” 100000”);
    vector<conf *> conflist;
    conflict.push_back(conf1);// [0]
    conflict.push_back(conf2);// [1]

    //strcpy_s(pconf1->itemname,sizeof(pconf1->itemname),”ServerName123”);

    // 查詢項目名字對應的內容
    char *p_tmp = getinfo(conflict,”ServerName”);
    if(p_item != nullptr)
    {
        cout << p_item << endl;
    }

    // 釋放內存
    std::vector<conf *>::iterator pos;
    for(pos = conflict.begin(); pos != conflict.end(); pos++)
    {
        delete (*pos); // *pos代表了conf的指針,刪除自己new出來的內存
    }
    conflict.clear();  // 這個要不要都行。 
    return 0;
}

叠代器精彩演繹,失效分期及彌補、實戰