This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
reducing needless normal_iterator usage in vector
- From: Phil Edwards <phil at jaj dot com>
- To: libstdc++ at gcc dot gnu dot org
- Date: Tue, 2 Jul 2002 09:10:11 -0400
- Subject: reducing needless normal_iterator usage in vector
At least, I think it's needless.
There are a few places in std::vector where we pass begin() and end() to
other member functions, using them in expressions where pointer arithmetic
would do just as well.
The reason is simply because that's how the code is in the HP/SGI codebase.
But they used raw pointers as their iterator typedef; typing "begin()"
was simply clearer code. Since we use a wrapper class for type safety,
there can be tiny performance hits, slowly accumulating. For simple uses,
the clarity doesn't seem to be worth the risk of extra code, especially
since "_M_start" is just as clear as "begin()".
Replacing simple expressions like "begin() + n" with "_M_start + n"
skips the normal_iterator ctor and the normal_iterator's overloaded ops,
and gets right to the pointer arithmetic that we eventually do anyway.
For example, changing
reference operator[](size_type __n) { return *(begin() + __n); }
to
reference operator[](size_type __n) { return *(_M_start + __n); }
gives us the following difference in the generated assembly. With begin():
std::vector<int, std::allocator<int> >::operator[](unsigned):
pushl %ebp
movl %esp, %ebp
pushl %ebx
subl $36, %esp
leal -8(%ebp), %ebx
leal -12(%ebp), %eax
movl %eax, (%esp)
movl 8(%ebp), %eax
movl %eax, 4(%esp)
call std::vector<int, std::allocator<int> >::begin()
subl $4, %esp
leal -12(%ebp), %eax
movl %ebx, (%esp)
movl %eax, 4(%esp)
movl 12(%ebp), %eax
movl %eax, -16(%ebp)
leal -16(%ebp), %eax
movl %eax, 8(%esp)
call __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >::operator+(int const&) const
subl $4, %esp
leal -8(%ebp), %eax
movl %eax, (%esp)
call __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >::operator*() const
movl -4(%ebp), %ebx
leave
ret
But with _M_start:
std::vector<int, std::allocator<int> >::operator[](unsigned):
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %edx
movl 12(%ebp), %eax
sall $2, %eax
addl (%edx), %eax
popl %ebp
ret
Note that I wrote "for simple uses" above; I'm proposing only to make the
change in small obvious functions. For larger member functions, I don't
think it matters, but that's only my opinion... much like the rest of this
message has been. :-)
Thoughts?
Phil
--
If ye love wealth greater than liberty, the tranquility of servitude greater
than the animating contest for freedom, go home and leave us in peace. We seek
not your counsel, nor your arms. Crouch down and lick the hand that feeds you;
and may posterity forget that ye were our countrymen. - Samuel Adams