2

What is the most efficient way to code "print all the elements of a vector to standard out" in C++,

for(std::vector<int>::iterator it = intVect.begin(); it != intVect.end(); ++i)
std::cout << *it;

or

std::copy(intVect.begin(), intVect.end(), std::ostream_iterator<int>(std::cout));

and why?

  • 3
    Are you unable to profile both and compare the results? – jweyrich Nov 28 '11 at 15:38
  • profiling is not the issue here. –  Nov 28 '11 at 15:50
  • 3
    Do you seriously think it matters? You're streaming out to a stream, the overhead of that operation will simply dwarf any looping overhead. Focus on clear-concise code that's easy to read and maintain. – Nim Nov 28 '11 at 15:50
  • come on people, please focus on the question, and answer. don't try to demote it as obsolete, and don't have in mind the servers at you local super computer systems. Please provide answers with justification. Thanks –  Nov 28 '11 at 15:58
  • @g24l: we're trying to help. Let's all try to stay gentle and polite. **[Software Profiling](http://en.wikipedia.org/wiki/Profiling_(computer_programming))** is a method used to collect data from your software while it's running. Storing this data then enables you to measure multiple indices of performance (be it speed, memory usage, etc), and analyse them to further decide whether part (or all) of your software is performing well or not. – jweyrich Nov 28 '11 at 16:10
  • You might wish to look [here][1], another question covering this subject. [1]: http://stackoverflow.com/questions/4850473/pretty-print-c-stl-containers – paul23 Nov 28 '11 at 16:14
  • @ jweyrich : Thank you for comment. I am looking for an analytic answer, that is why I said that I don't want to profile the code. That's obviously easy to do and I know this much. I just want to have a logical answer: e.g. the first portion of code is better because it generates less calls and will probably make a better, or copy() is better optimised to do this job, or whatever someone thinks. My knowledge is limited but I am certain we can be constructive. –  Nov 28 '11 at 16:17
  • 1
    Are you really trying to ask if there is a performance implication between using a hand-written `for` loop versus using the `std::copy` algorithm? – John Dibling Nov 28 '11 at 16:26
  • It is a good answer, I am thinking about it. :) –  Nov 28 '11 at 16:42

3 Answers3

7

You can use

http://louisdx.github.com/cxx-prettyprint/

and rely on the work of other people that made sure it will be most optimal.

Roman Byshko
  • 7,565
  • 5
  • 32
  • 54
  • 3
    +1. I liked that someone is also liking the utility. Its getting popular. Congrats @Kerrek SB – Nawaz Nov 28 '11 at 15:42
  • I am uncertain that your answer constitutes a response to "why" as well, and it seems vague to me. –  Nov 28 '11 at 15:48
  • @g24l Strictly saying that wasn't answer to your question but it was a recommendation how you can omit this dilemma. – Roman Byshko Nov 28 '11 at 15:50
  • 1
    Thanks for the props :-) Contributors welcome, by the way, especially for the C++98 version. Also comments on whether I got the ADL for `begin`/`end` right. – Kerrek SB Nov 28 '11 at 15:53
  • @ Roman B. Still it is not an answer, and I do not want to omit the dilemma, but clarify it. –  Nov 28 '11 at 18:25
  • @g24l Agree. Feel free to accept other one and downvote mine. – Roman Byshko Nov 28 '11 at 18:29
5

If you are asking which of methods you've posted will be faster, the only valid answer can be:

There is no way to know for sure because they are equivalent. You must profile them both and see for yourself.

This is because the two methods are effectively the same. The do the same thing, but they use different mechanisms to do it. By the time your compiler's optimizer has finished with the code, it may have found different opportunities to increase execution speed, or it may have found opportunities in each that result in identical machine code being executed.

For example, consider:

for(std::vector<int>::iterator it = intVect.begin(); it != intVect.end(); ++i)

At first blush, it might seem like this could have a built-in inefficiency by the fact that intVect.end() is evaluated at each loop. This would make this method slower than,

std::copy(intVect.begin(), intVect.end(), std::ostream_iterator<int>(std::cout));

...where it is only evaluated once.

However, depending on the surrounding code and your compiler's settings, it might be re-written so that it is only evaluated once, at the beginning of the for. (Credit: @SteveJessop) Or it might even be that it isn't hoisted, but evaluating it is no different from examining a pre-computed value. It's possible that either way, the emitted code must load a pointer value from (stack pointer) + (small offset known at compile time). The only way to know for sure is to compile them both and examine the resulting assembly code.

Beyond all of this however is a more fundamental issue. You are asking which method of doing something is faster, when the core thing you're trying to do is potentially very slow to begin with, relative to the means by which you do it. If you are writing to stdout using streams, it is going to have negligible effect on the overall execution time whether you use a for loop or std::copy even if one is marginally faster than the other. If your concern is overall execution time, you're possibly barking up the wrong tree.

Steve Jessop
  • 257,525
  • 32
  • 431
  • 672
John Dibling
  • 94,084
  • 27
  • 171
  • 303
  • 1
    "it might be re-written so that it is only evaluated once, at the beginning of the for" - or it might even be that it isn't hoisted, but evaluating it is no different from examining a pre-computed value. It's possible that either way, the emitted code must load a pointer value from (stack pointer) + (small offset known at compile time). – Steve Jessop Nov 28 '11 at 16:31
  • @Steve: Nice observation, may I incorporate your words in to my answer? – John Dibling Nov 28 '11 at 16:32
  • I think that is the correct answer with a few asterisks. (1) In both cases there is a loop that evaluates intVect.end() which in both cases should receive the same optimisation by the compiler. Also cout << *it, is virtually the same as *++out=*++in , which I assume to be implemented in the copy() internal loop. There should be some overhead for calling copy() but this should be considered negligible. I would also like that you omit the suggestion about profiling but that is your personal style. Thanks. –  Nov 28 '11 at 17:08
  • @g24l: Because, you know, most optimization is done purely a priori. (Hint: sarcasm.) This has nothing to do with personal style, and everything to do with tested methods that *work*. You want to speed something up? Find out how by *profiling*. If you don't want to accept peoples answers, why bother asking the question? And no, `copy` will almost certainly be *inlined*; that's one of those things you'd know from profiling. – GManNickG Nov 28 '11 at 19:08
  • @GMan: You claim that the generated code of a "for-loop" is larger than copy()'s ? I hope not. Also, about profiling, there is nothing wrong about it, except that it does not answer the question. e.g. How many wheels should a car have to be stable? 3,4,5. Your answer was let's build all cars and see which is stable. There is a difference between top-down and bottom-up approach. Nothing wrong about either, but for problems than can be decided/computed/inferred bottom-up is the way to do. Please don't troll any more. Thanks –  Nov 28 '11 at 22:33
  • @g24l: Your analogy is terrible. Better would be: "I have multiple sets of tires, which work best on my car?" Test them and find out. You think the tires race car drivers use aren't tested and optimized? They just figure it all out beforehand? And news flash: someone disagreeing with you doesn't make them a troll. – GManNickG Nov 28 '11 at 23:11
  • @GMan: Really, that is what you do when you have you car fitted with tires? you try them all on? seems like a waste of money and time to me. I'd better go ask an expert (e.g. SO people) what set of tires must be used on that car for that specific usage. I would avoid those that would tell me try them all on and see. (and admit it you are trolling, you are arguing on the analogy of an example) –  Nov 28 '11 at 23:48
  • @g24l: No, I cannot "admit" I am trolling because I simply am not. I am, however, finished with this discussion. – GManNickG Nov 29 '11 at 00:46
4

These two lines will end up doing essentially the same thing (almost definitely) once the compiler gets through with them. Either way you will end up with the same code looping through using iterators in range of {begin, end-1} using the same streams.

This is a micro-optimization that will not help you significantly, though I'm sure you can compile it with a big data set and see for yourself easily on your platform.

John Humphreys - w00te
  • 32,140
  • 30
  • 125
  • 230