Re: What is the output of this program?
Earl Purple wrote:
I made another post but it was full of bugs.
I don't want to pick on you, because you are being honest. But
don't you think that you've just given a clinching argument
against resize? :-) If it is that difficult to get right...
This one compiles and runs and is more what I had in mind:
#include <string>
#include <algorithm>
#include <ctime>
#include <cstdlib>
#include <stdexcept>
#include <iostream>
void pushbacking( std::string& s, const std::string & source )
{
s.reserve( source.size() );
std::copy( source.begin(), source.end(), std::back_inserter( s ) );
}
void resizing( std::string & s, const std::string & source )
{
s.resize( source.size() );
std::copy( source.begin(), source.end(), s.begin() );
}
void test( std::string const& fName, void f( std::string&, const
std::string & ), const std::string & source )
{
std::clock_t const startTime = std::clock();
std::string s = "knurre, voff!";
f( s, source );
std::clock_t const endTime = std::clock();
double const duration =
double(endTime - startTime)/CLOCKS_PER_SEC;
std::cout << fName << ": " << duration << " seconds." <<
std::endl;
}
int main()
{
try
{
const std::string::size_type stringSize = 10000000; // or whatever
number
std::string source ( stringSize, '*' );
test( "pushbacking", pushbacking, source );
test( "resizing", resizing, source );
return EXIT_SUCCESS;
}
catch ( const std::exception & x )
{
std::cerr << "Whoops " << x.what() << '\n';
return EXIT_FAILURE;
}
}
On VC8 in release mode:
pushbacking: 1.313 seconds.
resizing: 0.015 seconds.
Well, I don't find anywhere near this large of difference on my
machine. On the other hand, I do find more here (at home, on an
AMD 64 bit machine) than at work (on a Sun sparc). The
difference is obviously implementation dependent. Two comments,
however:
-- In all cases to date, the entire program and string fit into
main memory. Get a string which starts paging, and I'm
willing to bet that you'll get different results---resize
touches each byte twice, and has less locality than
push_back.
-- Your two functions do different things: pushbacking appends,
whereas resizing overwrites any initial value. And if you
just change s.begin() to s.end() in the copy, so that it
appends, your code is suddenly incorrect---you also have to
change the argument to resize(). Again: resize() is
fragile, push_back() isn't. Unless the profiler shows that
you don't have a choice, prefer the robust solution.
The point is that push_back requires bounds-checking at every
iteration and resizing does not.
And resize requires touching each element twice, and push_back
doesn't. It's six of one, and a half dozen of the other.
Depending on the architecture, how the compiler optimizes, how
big the strings are, how much memory is being used by other
applications, etc., etc., you may get different results.
The only thing likely to be slow in resizing is initialisation
(which shouldn't be a major problem with std::string).
If the strings are big enough that the difference between the
two is significant for the total runtime of the application, it
possibly could. In practice, in most cases, I wouldn't expect a
significant difference, and definitly prefer the improved
robustness of push_back.
(Of course, using a std::string member function might be a
better idea, but can you always be certain that your
collection is std::string?)
If you are supposing an arbitrary collection type (say, in a
template), how can you be sure that resize is faster.
As a general rule, there are standard idioms. The STL has been
designed with them in mind. Stick with them until the profiler
says you can't.
--
James Kanze kanze.james@neuf.fr
Conseils en informatique orient?e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S?mard, 78210 St.-Cyr-l'?cole, France +33 (0)1 30 23 00 34
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]