在顺序容器中添加元素

所有顺序容器都支持push_back 操作,提供在容器尾部插入一个元素的功能。下面的循环每次读入一个 string 类型的值,并存放在 text_word: 对象中:

// read from standard input putting each word onto the end of
container
string text_word;
while (cin >> text_word)
container.push_back(text_word);

调用 push_back 函数会在容器 container 尾部创建一个新元素,并使容器的长度加 1。新元素的值为 text_word 对象的副本,而 container 的类型则可能是 list、vector 或 deque。

除了 push_back 运算,list 和 deque 容器类型还提供了类似的操作:push_front。这个操作实现在容器首部插入新元素的功能。例如:

list<int> ilist;
// add elements at the end of ilist
for (size_t ix = 0; ix != 4; ++ix)
ilist.push_back(ix);

容器元素都是副本

在容器中添加元素时,系统是将元素值复制到容器里。类似地,使用一段元素初始化新容器时,新容器存放的是原始元素的副本。被复制的原始值与新容器中的元素各不相关,此后,容器内元素值发生变化时,被复制的原值不会受到影响,反之亦然。

在顺序容器中添加元素的操作

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 操作则提供了一组更通用的插入方法,实现在容器的任意指定位置插入新元素。

指定位置插入元素

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 函数返回指向新插入元素的迭代器。可使用该返回值在容器中的指定位置重复插入元素:

list<string> lst;
list<string>::iterator iter = lst.begin();
while (cin >> word)
iter = lst.insert(iter, word); // same as calling push_front

循环前,将 iter 初始化为 lst.begin()。此时,由于该 list 对象是空的,因此 lst.begin() 与 lst.end() 相等,于是 iter 指向该(空)容器的超出末端的下一位置。第一次调用 insert 函数时,将刚读入的元素插入到 iter 所指向位置的前面,容器 lst 得到第一个也是唯一的元素。然后 insert 函数返回指向这个新元素的迭代器,并赋给 iter,接着重复 while 循环,读入下一个单词。只要有单词要插入,每次 while 循环都将新元素插入到 iter 前面,然后重置 iter 指向新插入元素。新插入的元素总是容器中的第一个元素,因此,每次迭代器都将元素插入在该 list 对象的第一元素前面。

插入一段元素

svec.insert(svec.end(), 10, "Anna");

上述代码在容器 svec 的尾部插入 10 个元素, 每个新元素都初始化为 "Anna"。

在容器中插入由一对迭代器标记的一段范围内的元素:

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);

添加元素可能会使迭代器失效

在 vector 容器中添加元素可能会导致整个容器的重新加载,这样的话,该容器涉及的所有迭代器都会失效。即使需要重新加载整个容器,指向新插入元素后面的那个元素的迭代器也会失效。

任何 insert 或 push 操作都可能导致迭代器失效。当编写循环将元素插入到 vector 或 deque 容器中时,程序必须确保迭代器在每次循环后都得到更新。

避免存储 end 操作返回的迭代器

在 vector 或 deque 容器中添加元素时,可能会导致某些或全部迭代器失效。假设所有迭代器失效是最安全的做法。这个建议特别适用于由 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
first = v.insert(first, 42); // insert new value
++first; // advance first just past the element we added
}

 

posted @ 2018-05-04 16:18  刘-皇叔  阅读(597)  评论(0)    收藏  举报