C++順序容器中添加元素

添加元素相關操作:

--------------------------------------------------------------------------------------------------------

c.push_back(t) 在容器 c 的尾部添加值爲 t 的元素。返回 void 類型
c.push_front(t) 在容器 c 的前端添加值爲 t 的元素。返回 void 類型
只適用於 list 和 deque 容器類型.
c.insert(p,t) 在迭代器 p 所指向的元素前面插入值爲 t 的新元素。返回
指向新添加元素的迭代器
c.insert(p,n,t) 在迭代器 p 所指向的元素前面插入 n 個值爲 t 的新元素。
返回 void 類型
c.insert(p,b,e) 在迭代器 p 所指向的元素前面插入由迭代器 b 和 e 標記
的範圍內的元素。返回 void 類型

--------------------------------------------------------------------------------------------------------

在容器中指定位置添加元素
        使用 push_back 和 push_front 操作可以非常方便地在順序容器的尾部或首

部添加單個元素。而 insert 操作則提供了一組更通用的插入方法,實現在容器的

任意指定位置插入新元素。insert 操作有三個版本(表 9.7)。第一個版本需要一

個迭代器和一個元素值參數,迭代器指向插入新元素的位置。下面的程序就是使

用了這個版本的 insert 函數在容器首部插入新元素:
vector<string> svec;
list<string> slist;
string spouse("Beth");
// equivalent to calling slist.push_front (spouse);
slist.insert(slist.begin(), spouse);
// no push_front on vector but we can insert before begin()
// warning: inserting anywhere but at the end of a vector is an
expensive operation
svec.insert(svec.begin(), spouse);
新元素是插入在迭代器指向的位置之前。迭代器可以指向容器的任意位置,包

括超出末端的下一位置。由於迭代器可能指向超出容器末端的下一位置,這是
一個不存在的元素,因此 insert 函數是在其指向位置之前而非其後插入元素。

代碼
slist.insert(iter, spouse); // insert spouse just before iter
就在 iter 指向的元素前面插入 spouse 的副本。
這個版本的 insert 函數返回指向新插入元素的迭代器。可使用該返回值在
容器中的指定位置重複插入元素:
list<string> lst;
list<string>::iterator iter = lst.begin();
while (cin >> word)
iter = lst.insert(iter, word); // same as calling push_front
要徹底地理解上述循環是如何執行的,這一點非常重要——特
別是要明白我們爲什麼說上述循環等效於調用 push_front 函
數。
循環前,將 iter 初始化爲 lst.begin()。此時,由於該 list 對象是空的,
因此 lst.begin() 與 lst.end() 相等,於是 iter 指向該(空)容器的超出末
端的下一位置。第一次調用 insert 函數時,將剛讀入的元素插入到 iter 所指
向位置的前面,容器 lst 得到第一個也是唯一的元素。然後 insert 函數返回
指向這個新元素的迭代器,並賦給 iter,接着重複 while 循環,讀入下一個單
詞。只要有單詞要插入,每次 while 循環都將新元素插入到 iter 前面,然後
重置 iter 指向新插入元素。新插入的元素總是容器中的第一個元素,因此,每
次迭代器都將元素插入在該 list 對象的第一元素前面。
插入一段元素
insert 函數的第二個版本提供在指定位置插入指定數量的相同元素的功能:
svec.insert(svec.end(), 10, "Anna");
上述代碼在容器 svec 的尾部插入 10 個元素,每個新元素都初始化爲 "Anna"。
insert 函數的最後一個版本實現在容器中插入由一對迭代器標記的一段範
圍內的元素。例如,給出以下 string 類型的數組:
string sarray[4] = {"quasi", "simba", "frollo", "scar"};
可將該數組中所有的或其中一部分元素插入到 string 類型的 list 容器中:
// insert all the elements in sarray at end of slist
slist.insert(slist.end(), sarray, sarray+4);
list<string>::iterator slist_iter = slist.begin();
// insert last two elements of sarray before slist_iter
slist.insert(slist_iter, sarray+2, sarray+4);
添加元素可能會使迭代器失效
正如我們在第 9.4 節中瞭解的一樣,在 vector 容器中添加元素可能會導
致整個容器的重新加載,這樣的話,該容器涉及的所有迭代器都會失效。即使需
要重新加載整個容器,指向新插入元素後面的那個元素的迭代器也會失效。
任何 insert 或 push 操作都可能導致迭代器失效。當編寫循
環將元素插入到 vector 或 deque 容器中時,程序必須確保迭
代器在每次循環後都得到更新。
424
避免存儲end 操作返回的迭代器
在 vector 或 deque 容器中添加元素時,可能會導致某些或全部迭代器失
效。假設所有迭代器失效是最安全的做法。這個建議特別適用於由 end 操作返
回的迭代器。在容器的任何位置插入任何元素都會使該迭代器失效。
例如,考慮一個讀取容器中每個元素的循環,對讀出元素做完處理後,在原
始元素後面插入一個新元素。我們希望該循環可以處理每個原始元素,然後使用
insert 函數插入新元素,並返回指向剛插入元素的迭代器。在每次插入操作完
成後,給返回的迭代器自增 1,以使循環定位在下一個要處理的原始元素。如果
我們嘗試通過存儲 end() 操作返回的迭代器來“優化”該循環,將導致災難性
錯誤:
vector<int>::iterator first = v.begin(),
last = v.end(); // cache end iterator
// diaster: behavior of this loop is undefined
while (first != last) {
// do some processing
// insert new value and reassign first, which otherwise would
be invalid
first = v.insert(first, 42);
++first; // advance first just past the element we added
}
上述代碼的行爲未定義。在很多實現中,該段代碼將導致死循環。問題在於
這個程序將 end 操作返回的迭代器值存儲在名爲 last 的局部變量中。循環體
中實現了元素的添加運算,添加元素會使得存儲在 last 中的迭代器失效。該迭
代器既沒有指向容器 v 的元素,也不再指向 v 的超出末端的下一位置。
不要存儲 end 操作返回的迭代器。添加或刪除 deque 或
vector 容器內的元素都會導致存儲的迭代器失效。
爲了避免存儲 end 迭代器,可以在每次做完插入運算後重新計算 end 迭代器
值:
// safer: recalculate end on each trip whenever the loop adds/erases
elements
while (first != v.end()) {
// do some processing
425
first = v.insert(first, 42); // insert new value
++first; // advance first just past the element we added
}

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