Container that does not invalidate iterators (and pointers)

假如想象 提交于 2021-02-10 08:50:31

问题


I am currently looking for container that provides some inserting (insert or push_back) and some removing (erase, pop_back is not sufficient) methods, and that does not invalidate iterators nor pointers when calling these two methods.

More clearly, I want a set of elements where I can add an element (I do not care where), and where I can remove any element (so I do care where). In addition, I would have external pointers to specific elements, and I want them to remain valid if I add or remove an element from the set.

There are, to my knowledge, two standard containers that answer my needs : set and list. However, generally speaking, I do not like to use such containers for such simple needs. Since a list is involving pointers internally and does not provide random access to its elements, I think it is not a good choice. A set has random access to its elements, but is also involving pointers, and the random access itself is not done in constant time. I think that a set would be a better solution than a list, but I have thought about something else.

What about a simple vector that does not try to keep the elements contiguous when an element is removed ? When removing an element in the middle of this container, its position would be empty, and nothing else would happen. This way, no iterator or pointer would be invalidated. Also, when adding an element, the container would search for an empty position, and use a simple push_back if there is no such hole.

Obviously, since push_back can invalidate iterators with a vector, I would use a deque as the basis of implementation. I would also use some sort of stack to keep track of the holes from removing elements. This way, adding, removing, and accessing an element would be done in constant time, in addition to satisfying my no-invalidation needs.

However, there is still one problem : when iterating over this container or simply accessing an element by index we would need to take the holes into account. And that is where the problems start to surpass the advantages.

Hence my question : what do you think about my idea for that container ? More importantly, what would you use for my original problem, a set, a list or something else ? Also, if you have a nice and clean solution to the last problem (iterating over my container), feel free to show me.


回答1:


Requirement 1: inserting (insert or push back) and some removing (erase, and not only the last element)

  • Compliant candidates: deque, forward_list, list, map, multi_map, set, multiset, unordered_map, unordered_multimap, unordered_set, unordered_multiset, and vector

  • Eliminated candidates: array (no insert or push_back), queue, priority_queue and stack (no erase, only pop)

Requirement 2: does not invalidate iterators nor pointers when calling these two methods

  • Compliant candidates from also satifying requirement 1: forward_list, list, map, multi_map, set, multiset,
  • Eliminated on erase: deque (iterator remain valid only when erasing first element), and vector (all elements after the start of erasure)
  • Eliminated on insert: dequeue (in most of the cases), unordered_map, unordered_multimap, unordered_set and unordered_multiset (in case the growth requires a rehash) and vector (in case growth requires of reallocation)

Requirement 3: External pointers shall remain valid

Approximaletly the same result than for requirement 2. However unordered_map, unordered_multimap, unordered_set and unordered_multiset would satifsy this requirements because references to elements remain valid.

Requirement 4: Random access to elements

  • Complying candidates satisfying requirement 1 and 2: map and multimap
  • Almost complying candidates: set and multiset do not have a random access, but can satisfy it using member find() (O(logn))
  • Non compliant: list (although algorithm find() could provide a workaround in O(n)).

Answer to question 1: Which is better, a set or a list ?

It depends on your other requirements. In a set each value can only be stored once. If your elements are all unique , choose the set. If not you'd better opt for the list or the multiset.

I do not know the elements that you're storing, but is the whole element the search argument ? Or is there a key ? In the latter case, you'd really go for a map.

Answer to question 2: What about alternative container ?

I wouldn't opt for deque for your alternative.

If you can foresee the maximum number of elements, you could simply reserve enough capacity to avoid reallocation. (satisfying requirement 1, 3 and 4). If you have an "empty element" to represent holes, you could then also satisfy requirement 2. In worst case you could opt for a vector sotring your element and an indicator if it's valid.

If such a maximum is not determinable, I'd rather go for a map which proves to be flexible and satisfy all your requirements.



来源:https://stackoverflow.com/questions/28392443/container-that-does-not-invalidate-iterators-and-pointers

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!