?
=?iso-8859-1?q?Elias_Salom=E3o_Helou_Neto?=
(Strange, I didn't have any problem with his wording. But I'm
not sure any of us are native speakers here, although I did grow
up in America.)
Well, shame on me. My reading was awful and the wording was ok. Sorry
about that.
By definition, the difference between a constructor and an
assignment operator is that the assignment operator has an old
value, which must be taken into consideration. Sometimes,
taking it into consideration can actually improve performance;
e.g. if you are using deep copy, and the destination string is
smaller than the source. Other times, it can slow things down:
anytime it's not big enough, for example, and so must be freed,
and re-allocated, or if you're using copy on write.
The fact is that destructors will have to deal with the old value
anyway when iterating over a loop.
Depending on what you're doing with std::string, copy on write
can represent a significant performance gain, or a small (or
maybe not so small, in the case of multi-threaded code) loss.
The actual measurements were made some time ago, with g++
2.95.2, which didn't support threading at all, and had a small,
simple and very, very robust implementation of basic_string. My
own experiments suggest that they probably made the right trade
off using copy on write in this case, at least for my code.
That's what g++ does. It still means that you have to do
something with the old data.
Well, the fact that assignement is replaced by a full construction/
destruction cycle within the loop doesn't quite remedy that. What does
the destructor do with the data? There is no way around it unless we
do not want to release memory.
And I ask you how much experience you've actually had compiling
and optimizing C++, in order to make such a blanket statement.
I work designing and implementing heavy algorithms for image
reconstruction in tomography (I also prove they converge). And I have
been using C++ for a while, for Matlab was becoming too slow. One
thing I have learned is that if your class carries lots of data and
you don't want to go through implementing reference counted copy on
write, copy constructors should better be avoided, specially the
implicit ones, but this is not the point.
The standard contains a couple of special rules, just to permit
optimization of temporaries when constructing. They don't
necessarily apply when copying.
I guess you mean "when assigning", right? This is just the reason why
I say that with str( someFunction() ) wthe compiler removes
temporaries easier than in str = someFunction(). But if named objects
can't be optimized away (it would be handy if you could point me to
the "couple of special rules" in the standard), we can't even always
apply RVO when the function may do something very complex with the
object. How could I create the string of my last posting within a
return statement? Not to mention more complicated cases.
It's expecting automatically that one idiom will be faster than
the other, without actually having measured the specific case in
question, which is dumb. It's choosing a particular idiom on
the grounds that it will be faster without having measured.
Of course it is, but people here seems to religiously prefer T
t( someFunction() ) over someFunction( t ) even within tight loops and
for absolutely every class. So, are they dumb?
The problem is that you still don't understand. To start with,
your version doesn't use RVO, because there is no return value.
That was a typo. RVO should not be there.
And anyone with any real experience will automatically disagree
when you claim differences without actually having measured, and
will disagree that the measurements you made for one case apply
to the next.
But you measured, right? I was trying to understand the reasons for
something that seemed unlikely to happen, at least from my point of
view.
In fact,I am still not convinced, as I have never actually seen an
example in which "repeated construction/destruction cycles" could not
be replaced with performance gain by "creating outside the loop and
passing the object as reference". There may be, I look forward to see,
but have never seen. Perhaps, with your knowledge of std::string
internals, you could craft one for us. I would appreciate that.
You claim to have an ancient piece of code where your idiom used to
perform better than "creating once and repeatedly assigning", but this
is not what I want.
Let us make things clear. I am not here claiming that this is always
the way to go. One must, for sure, try several solutions. However
trying every possibility is not usually feasible, and one should try
those which are more likely to work well. This is why it is worth to
know why your code behaved like that, if it could have been improved,
and such.
Elias Salomão Helou Neto.