[Patch] libstdc++/23425
Howard Hinnant
hhinnant@apple.com
Fri Nov 4 15:20:00 GMT 2005
On Nov 4, 2005, at 5:05 AM, Paolo Carlini wrote:
> Paolo Carlini wrote:
>
>
>> Hi,
>>
>>
>>> lear() is best not thought of as a special case of erase(). It is
>>> best thought of as a special case of a private function which
>>> I'll call:
>>>
>>> void __erase_at_end(size_type n);
>>>
>>> Erases the last n elements from the vector. This is needed in the
>>> following public members of vector:
>>>
>>> All forms of assign.
>>> All forms of erase.
>>> All forms of resize.
>>> clear.
>>>
>>>
>>>
>> Howard, makes sense to you that essentially the same optimization is
>> possible for std::deque? I'm looking at the code and, besides the
>> additional complexity of freeing the nodes, it seems everything is
>> very,
>> very similar. I can work on that too in the branch.
>>
>>
>>
> + understandably, an _M_erase_at_begin could be expected...
>
> However I'm not sure that it would find as many uses, besides the
> implementation of erase(iterator, iterator)...
Ay, a really good deque is head&shoulders the most complicated
container in the lib. Far, far more complicated than the rb tree.
Yes, _M_erase_at_end would be useful under assign, pop_back, erase,
and resize. A good _M_erase_at_end will do more than simply run the
iterator through. It will do the "segmented iterator" optimization
as promoted by Dietmar for so many years. That is, it will consist
of nested loops where the inner loop runs through a node (or partial
node) at a time with pointers. And I'm not sure what the node-
freeing policy is for our deque. Imho it is a good idea to leave an
empty node out there on the end because the very next thing is either
going to be a push_back, requiring the node again, or a push_front
which could (if it needed) transfer the empty node from back to front.
And here is where we really, really need a quality
has_trivial_destructor. So much so, that we should go ahead and use
whatever we have. The trivial dtor version of _M_erase_at_end can't
be optimized by the compiler. This version can completely eliminate
the inner loop and just concentrate on freeing nodes and adjusting
the size.
_M_erase_at_begin? Yup. Same comments, but useful only under
pop_front and erase. Given that for pop_front to call erase is
overkill for code and speed (it can merely call _M_erase_at_begin(1)
or whatever), and there are two versions of erase that can make use
of _M_erase_at_begin, I think it is a good deal (especially if it is
optimized to the hilt with segmented iterator and trivial dtor).
deque is a bear. And I've barely looked at ours. But I've looked at
it enough to have the opinion that it might benefit from some major
surgery, not the least of which is it's overhead: sizeof(deque<int>)
is 40 (on a 32 bit machine). I think we can get that down some. The
CodeWarrior deque is 24. Now it may be that we don't go that far
down. As I recall there are some tradeoffs with iterator as you
squeeze the size of the deque. But I think it is an area that
wouldn't hurt from some review.
And of course this all needs to be done without breaking exception
safety. Do we run (and pass) Abrahams exception safety test?
Additionally, if we don't already have it, we could use some
exception safety tests that stress the corner cases of adding,
deleting, transferring nodes both on empty deques and non-empty
deques. <sigh> Last time I fooled with deque it was a multi-month
project...
I encourage you to go ahead with _M_erase_at_end/_M_erase_at_begin.
If we are going to change the size at all, it couldn't be until v7
anyway.
-Howard
More information about the Libstdc++
mailing list