问题
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
, andvector
Eliminated candidates:
array
(noinsert
orpush_back
),queue
,priority_queue
andstack
(noerase
, onlypop
)
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), andvector
(all elements after the start of erasure) - Eliminated on insert:
dequeue
(in most of the cases),unordered_map
,unordered_multimap
,unordered_set
andunordered_multiset
(in case the growth requires a rehash) andvector
(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
andmultimap
- Almost complying candidates:
set
andmultiset
do not have a random access, but can satisfy it using memberfind()
(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