8

This program:

#include <iostream>
#include <cstdlib>
#include <string>

int main(int argc, const char *argv[])
{
   using ::std::cerr;
   using ::std::cout;
   using ::std::endl;

   if (argc < 2 || argc > 3) {
      cerr << "Usage: " << argv[0] << " [<count>] <message>\n";
      return 1;
   }
   unsigned long count = 10000;
   if (argc > 2) {
      char *endptr = 0;
      count = ::std::strtoul(argv[1], &endptr, 10);
      if ((argv[1][0] == '\0') || (*endptr != '\0')) {
         cerr << "Usage: " << argv[0] << " [<count>] <message>\n";
         return 1;
      }
   }
   const ::std::string msg((argc < 3) ? argv[1] : argv[2]);
   for (unsigned long i = 0; i < count; ++i) {
      cout << i << ": " << msg << '\n';
   }
   return 0;
}

when timed like so:

$ time ./joe 10000000 fred >/dev/null

real  0m15.410s
user  0m10.551s
sys   0m0.166s

takes 15.4 seconds of real time to execute. Replace the output line with this: cout << i << ": " << msg << endl; and you end up with something like this:

$ time ./joe 10000000 fred >/dev/null

real  0m39.115s
user  0m16.482s
sys   0m15.803s

As you can see, the time to run more than doubles, and the program goes from spending minimal time in the OS to spending nearly half of it's time in the OS.

Both versions of the program have identical output, and are guaranteed by the standard to have identical output on every platform.

Given this, why do people persist in using endl as a synonym for '\n'?

Edit: In case it isn't obvious, this question is intended to be a leading question and is here for instructional purposes. I know why the performance penalty exists.

Omnifarious
  • 54,333
  • 19
  • 131
  • 194

6 Answers6

21

I'm not certain. Inserting std::endl into the output stream is defined as being equivalent to inserting .widen('\n') and then calling flush() and yet many programmers persist in using std::endl even when there is no cause to flush, for example they go on to immediately output something else.

My assumption is that it comes from an incorrect belief that it is somehow a more portable because it doesn't explicitly use a specific newline character. This is incorrect as \n must always be mapped to the system's correct newline sequence for non-binary files by the stream library.

Omnifarious
  • 54,333
  • 19
  • 131
  • 194
CB Bailey
  • 755,051
  • 104
  • 632
  • 656
  • 2
    You know, you are the first person who gave an actual answer. :-) Asking leading questions gets you nowhere on this site. I need to find a better way of stating questions I intend to be instructional. – Omnifarious Jan 23 '10 at 11:55
  • I gave an actual answer too, as it happens. You may not agree with it, of course. –  Jan 23 '10 at 12:00
  • @Neil Butterworth, Oh, alright. Yes, Charles is the second person to give an actual answer. :-) Yours is too. – Omnifarious Jan 23 '10 at 12:03
  • Also, strictly speaking my answer isn't completely assumption; it's an extraction from an incredibly small sample size of developers I've talked to about this. The extrapolation probably has a very shaky statisical validity. – CB Bailey Jan 23 '10 at 12:09
  • Interest in this question has faded, and you definitely have the best answer, with actual real data to back it up. :-) – Omnifarious Jan 24 '10 at 18:56
4

Not everyone cares so much about performance. For some applications, guaranteeing the stream is flushed is much more important.

Edit: Also, I find endl easier to type than '\n' :-)

  • In almost no case where I see `endl` used does it actually matter if the stream is flushed right then and there. :-) – Omnifarious Jan 23 '10 at 11:40
  • Logging applications, network communications and databases come immediately to mind. –  Jan 23 '10 at 11:43
  • People should be using `::std::cerr` or some other unbuffered stream for logging. I've never seen a serious network application or database that used iostreams for communication over the network or writing to the database. – Omnifarious Jan 23 '10 at 11:47
  • You are the first person to give an actual answer, though I disagree with it. :-) – Omnifarious Jan 23 '10 at 12:05
  • There are very few uses were performance and stream are required in the same application. In which case it is generally easier to be consistant and use std::endl (apart from example programs to demonstrate the difference). Do I really care if an application takes 15 or 30 seconds. – Martin York Jan 23 '10 at 12:49
  • Actually Martin, that's my point, if your using std::iostream, then u did'nt care so much about performance, and if you care about performance, you didn't care too much about portability, so there's really few cases when you care about both things, so u have to worry for using proper newline character instead of std::endl – erick2red Jan 23 '10 at 16:25
  • @erick2red, except '\n' isn't any less portable than endl. THere is no portability performance tradeoff in using it. IMHO, it's completely senseless to use endl. People almost never need to actually flush the stream when they use it, they just saw it in a book and do it that way now without thinking or understanding the difference. – Omnifarious Jan 24 '10 at 19:01
4

Afaik, endl also flushes the stream, which may be the cause of the performance penalty.

helpermethod
  • 59,493
  • 71
  • 188
  • 276
  • You are right. std::endl flushes the output buffer, and "\n" does not. – Mark Byers Jan 23 '10 at 11:41
  • I know why the performance penalty exists. :-) My question is: Why is `::std::endl` still just "what's done" even though it has that performance penalty? – Omnifarious Jan 23 '10 at 11:52
  • 1
    Probably because most programmers like it when their user can see the output instead of forcing them to wait until the buffer fills up. Given the speed of real output devices, it never really matters. – Hans Passant Jan 23 '10 at 12:11
2

I tend to use endl with on stringstreams as it makes it easy to spot missing linebreaks.

josefx
  • 15,506
  • 6
  • 38
  • 63
2

My guess is that instructional texts use std::endl with the belief that it's simpler and less confusing for beginners, and afterward people got accustomed to using it.

jamesdlin
  • 81,374
  • 13
  • 159
  • 204
0

The real question is, why did the compiler make such a dogs breakfast of compiling the endl version? If they're guaranteed to have the same semantics, then they should also have the same runtime.

Edit: obviously, I wasn't aware that endl flushed the stream... that's what you get for not looking it up.

Andrew McGregor
  • 31,730
  • 2
  • 29
  • 28
  • They, in fact, most definitely do not have the same semantics. – Omnifarious Jan 23 '10 at 11:41
  • Well, they could do, they are just not guaranteed to by the C++ Standard. –  Jan 23 '10 at 11:43
  • @Neil Butterworth, the standard allows `::std::cout` to be unbuffered? – Omnifarious Jan 23 '10 at 11:58
  • 1
    No, but the standard does not specify what the effect of outputting '\n' is. –  Jan 23 '10 at 12:03
  • 1
    @Neil Butterworth, Ahh. *laugh* I suppose there's precedent. The stdio library in C treats '\n' specially and auto-flushes when it's encountered. They call it 'line buffering'. – Omnifarious Jan 23 '10 at 12:09
  • On many unixes, `std::cout` and `stdout` are line buffered only when the output is connected to an interactive terminal and not (e.g.) when attached to a file or other devices. – CB Bailey Jan 23 '10 at 12:11