How do you add a new line in C++? Chris Sharpe suggests std::endl is a tiny utility that’s more trouble than it’s worth.
Just what am I complaining about?
I wanted to write about a particular bad habit I always see from students and C++ beginners, especially in questions on Stack Overflow , that seems to be taught in a lot of books, online tutorials, classes, etc.
Do you use
std::endl
to end lines when streaming text? Do you know what it does?
std::cout << "Foo" << std::endl;
std::endl
does two things:
-
writes
'\n'
to the stream - flushes the stream [ cppreference-1 ].
And nothing else. I’ve seen people mention that it is the right thing to use to get cross platform line endings. This is just wrong; streaming
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, it is wrong for such a utility to exist.
Why use std::endl?
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 character. 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
[ cppreference-2 ] 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 [ cppreference-3 ], so this will happen automatically. (Note they are also synced with the C equivalents [ cppreference-4 ]). - 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
[
linux-1
]), basic console output is not the best thing, and you should use a toolkit such as ncurses [
linux-2
]. But let’s say you are just writing a basic example, like the pendulum simulator in Listing 1. What should you use in that case?
while (true) { std::cout << "Tick" << std::endl; sleep(1); std::cout << "Tock" << std::endl; sleep(1); } |
Listing 1 |
Why NOT use std::endl?
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 of
std::cout
are line-buffered when writing to an actual terminal, for instance
libstdc++
(default with gcc) [
GNU
], but of course you can’t 100% rely on that and remain completely cross-platform.
So I’ve argued that writing a newline and flushing a stream are unrelated operations, and you rarely want to do the latter anyway. But maybe you do occasionally want to do both at the same time. Isn’t
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.
What should I do instead?
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 (Listing 2:
namespace cds { char const nl = '\n'; } // ... std::cout << "Tick" << cds::nl << std::flush; |
Listing 2 |
or you can model it on more closely on
std::endl
(Listing 3).
namespace cds { std::ostream& nl(std::ostream& os) { return os << '\n'; } } // ... std::cout << "Tick" << cds::nl << std::flush; |
Listing 3 |
If you stream a function that takes and returns an
std::ostream&
, the function is called on the stream.
My argument is simply about writing expressive code – code that says what you mean and means what you say. If you don’t find that convincing, many other people have also raised the genuine performance problem all the extra flushing can cause [
Kuhl12
], [
Stroustrup
] and [
Turner16
]. (The first of those links also provides another
nl
manipulator, that will work on streams with a character type other than
char
.)
References
[cppreference-1] endl: https://en.cppreference.com/w/cpp/io/manip/endl
[cppreference-2] unitbuf: http://en.cppreference.com/w/cpp/io/manip/unitbuf
[cppreference-3] tie: https://en.cppreference.com/w/cpp/io/basic_ios/tie
[cppreference-4] stdio: https://en.cppreference.com/w/cpp/io/ios_base/sync_with_stdio
[GNU] Buffering: https://gcc.gnu.org/onlinedocs/libstdc++/manual/streambufs.html#io.streambuf.buffering
[Kuhl12] Dietmar Kuhl ‘stop excessive use of std::endl’, 14 January 2012, https://kuhllib.com/2012/01/14/stop-excessive-use-of-stdendl/
[linux-1] top: https://linux.die.net/man/1/top
[linux-2] ncurses: https://linux.die.net/man/3/ncurses
[Stroustrup] Bjorn Stroustrup and Herb Sutter (editors), C++ Core Guidelines , https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Rio-endl
[Turner16] Jason Turner (2016) ‘C++ Weekly – Ep 7 Stop Using std::endl’, at https://www.youtube.com/watch?v=GMqQOEZYVJQ
herding cats leading a team, juggling, and being a domestic servant to two huskies, Chris Sharpe occasionally finds time to write C++ at Bloomberg L.P.
In between