$include_dir="/home/hyper-archives/boost/include"; include("$include_dir/msg-header.inc") ?>
From: rwgk (rwgk_at_[hidden])
Date: 2002-03-06 17:50:50
--- In boost_at_y..., "Stewart, Robert" <stewart_at_s...> wrote:
> From: rwgk [mailto:rwgk_at_y...]
> >
> > --- In boost_at_y..., "Stewart, Robert" <stewart_at_s...> wrote:
> > > > Unfortunately the reserve() solution eventually requires
> > > > use of push_back(), which is also slow.
> > >
> > > If you use push_back() following reserve(), there is no
performance
> > penalty.
> > > The push_back()'ed object is copied into the next element. If
you
> > exceed
> > > the size allocated with reserve(), then push_back() will cause
> > reallocation
> > > and copying, so be sure to choose the right size when calling
> > reserve().
> >
> > Here is an example push_back() implementation:
> >
> > void push_back(const ElementType& x) {
> > if (size() < capacity()) {
> > new (end()) ElementType(x);
> > m_incr_size(1);
> > }
> > else {
> > m_insert_overflow(end(), size_type(1), x, true);
> > }
> > }
> >
> > I doubt that the optimizer can entirely remove the
> > overhead associated with incrementing the size,
> > and it can certainly not remove the "if" statement.
>
> The memory for the vector is not reallocated, and the elements are
not
> copied from the old to a new allocation. That is, with a judicious
call to
> reserve() before push_back(), size() < capacity() will always be
true, so x
> will be copied into the uninitialized memory at end() and the size
will be
> incremented. Thus, there is no memory/copy performance penalty
which is
> what I thought "slow" was meant to imply. If a comparison of two
integers
> and the increment of another is more overhead than you can bear --
though it
> certainly doesn't justify the label "slow"! -- then you need a
fixed-size
> array such as a C array or a wrapper class of a C array.
I agree that the overhead for std::vector will probably not be
noticeable in most applications and on most CPUs. But sometimes
people mention that an if-statement inside a loop causes
certain CPU-specific optimizations/advantages to break down.
I.e., the performance degrades disproportionally. I am not
sure how true this still is for modern CPUs.
The other point is that the code above is from a reference
counted container implementation. size(), capacity() and end()
look up member data of a separate object (the handle that
maintains the reference count and the memory). In this
situation you really have to think twice before using
push_back().
Back to the original question of changing the default
constructor of std::complex (to not initialize the
data members): this would mean that, e.g.:
std::complex<double>()
behaves differently than
double()
B. Stroustrup writes (section 6.2.8 of The C++ Prog. Lang.):
"The value of an explicit use of the constructor for a
built-in type is 0 converted to that type."
IMO std::complex<double>() and double() should behave
the same way.
Back to the question of initializing vectors of
std::complex: IMO the relevant container types
(vector, valarray, anything else?) should provide
a facility (constructor) to set the size() without
initializing the values if possible, i.e. if the
value_type has a trivial destructor (this is more general
than the requirement that the value_type is a POD
type). A couple of hours ago I posted a suggestion
for this that has unfortunately not yet shown up...
(but see the recent replies from David under the same
subject).
Ralf