Post

for range loop

使用for range loop有个潜在的意思,就是你不要在中间再修改这个容器的大小,尤其不要随便操作迭代器

for range loop等价于实现了begin和end的容器在做一个

1
for(it = begin();it != end();it++)

这个时候如果你要改删除迭代器或者扩容,很可能出问题。尤其要注意在代码逻辑中,一些看似异步的回调,可能很快有sync的操作

在sync操作的时候删除了迭代器,就会出问题

比如欣赏一个sigslot的case,讲道理,emit sig的地方不应该主动的删除掉slot,但架不住工程太大了,比较容易出问题

1
2
3
4
5
6
7
8
9
10
void emit(args... a) {
#if defined(SIGSLOT_ENABLE_THREAD_AFFINITY)
  check_thread_affinity();
#endif
  internal::lock_block<mt_policy> lock(&(this->m_policy));
  // auto connected_slot = this->m_connected_slots;
  for (const auto& slot : this->m_connected_slots) {
    slot->emit(a...);
  }
}

slot->emit的时候如果把操作了当前的m_connected_slots,结果是ub的

迭代器失效

序列的容器都有可能,vector和deque这种可能引起后续元素重排这种,或者扩容导致整体全部移动了, list还好,后续的迭代器不会失效

set和map这种红黑树的结构,属于关联容器,其实也还好,只会导致当前失效

list删除当前迭代器,当前迭代器就无效了,再对它进行操作就可能出问题

不想动脑子的话,拿到迭代器之后,如果你要删除或者扩容,就不要再用这个迭代器了,因为它可能失效了

  1. 综合的来讲,删除的时候都需要考虑下,扩容过的时候序列的要考虑下

  2. 另外如果一个容器会扩容,尽量不要拿容器back的指针,因为扩容之后会导致之前拿的back的指针失效

This post is licensed under CC BY 4.0 by the author.

Trending Tags