These are:
using namespace std;
std::cout << "Foo" << std::endl;
(or worsecout << "Foo" << endl
).
Do you use
std::endl
to end lines when streaming text? Do you know what it does?std::endl
does two things:- writes
'\n'
to the stream. - flushes the stream.
std::endl
is guaranteed to do the same thing as streaming '\n'
, and platforms make their own guarantees about expanding this into their canonical line endings (for instance, it becomes <CR><LF>
on Windows). std::endl
exists in the Standard Library only for those situations where you want to both write a newline character and flush the stream. I think, with the benefit of hindsight, this is wrong.In my mind, these are two entirely unrelated operations. The first is simply writing a character to the target underlying the stream, no more special than any other. The second is an administrative action on the stream object itself, and one that I have rarely seen a good reason to carry out manually. Why would you want to do both at once? Some possibilities:
-
You have some urgent output you want the user to see immediately. Sounds like a perfect case for
std::cerr
, which hasunitbuf
set so will display all output immediately and never needs to be manually flushed, entirely for this purpose.
-
You want to display a prompt and make sure it appears before asking for input.
std::cout
andstd::cin
aretie
d together, so this will happen automatically. (Note they are also synced with theC
equivalents).
-
You want some sort of live updating output that is not urgent per se, and is not part of user interaction (interleaved with reading). Well it may be the case that for a live updating UI (e.g.
top
), basic console output is not the best thing, and you should use a toolkit such as ncurses. But let’s say you are just writing a basic example, like this pendulum simulator:
while (true) { std::cout << "Tick" << std::endl; sleep(1); std::cout << "Tock" << std::endl; sleep(1); }
Ok, now I’ve painted myself into a corner where you might legitimately want to flush the stream each time. But the delimiter is still irrelevant to the flushing. What if you decided to separate the ticks with spaces or tabs instead? And anyway, many implementations ofstd::cout
are line-buffered when writing to an actual terminal, for instance libstdc++ (default with gcc), but of course you can’t 100% rely on that and remain completely cross-platform.
std::endl
ideal for that?I’d still argue no. It’s very important to clearly express your intent in code. Comments are important of course, but it’s even better when they simply aren’t necessary. Comments can be out of date. The code can’t. Now many beginners (and some more experienced programmers, sadly) simply don’t know that
std::endl
flushes. So when I see it used, I simply have no idea if the original author really intended to flush or not. I see many uses of std::endl
where flushing makes absolutely no sense whatsoever, and plenty of uses where it is certainly not clear that flushing is useful.So what do I recommend? Use
'\n'
, and std::flush
if you really do mean it. You may as well put the '\n'
into the preceding string literal while you are at it.std::cout << "foo\n"; std::cout << "Some int: " << i << '\n'; std::cout << "bar\n" << std::flush;If your printing is a bit convoluted and you really do want to make it clear where you are printing a newline, you can separate it from the preceding string literal, and even give it a name if you like:
namespace cds { char const nl = '\n'; } // ... std::cout << "Tick" << cds::nl;Or you can model it on more closely on
std::endl
:namespace cds { std::ostream& nl(std::ostream& os) { return os << '\n'; } } // ... std::cout << "Tick" << cds::nl;If you stream a function that takes and returns an
std::ostream&
, it is called on the stream.And this is without mentioning the genuine performance problem all the extra flushing can cause. (Dietmar also provides a better
nl
manipulator, that will work on streams with a character type other than char
).
Nice article, mind if I link to this on SO when needed?
ReplyDeleteGo right ahead, that's why I wrote it.
Delete