The importance of std::endl in C++
As it turns out, it’s a bit more than a verbose \n
The semester is wrapping up, and so like many students, I’m rushing to finish projects that I could have started weeks ago, but elected not to. I spent the past few years as a teacher, constantly getting on students’ cases about them waiting too long to start working on projects… turns out I’m no better!
Anyway, in the process of working on one of these projects, I made an
interesting discovery about C++ and how important std::endl
is when you are
using std::cout
to produce program output.
The assignment in question involves a writing distributed shared memory system, and then verifying that it works using some provided test clients. In particular, I was fighting with a distributed sort-merge implementation when I noticed some strange behavior regarding my output.
To verify that it works properly, the test client writes the sorted array to stdout using something like the following,
for (int i = 0; i < ELEMENT_CNT; i++)
std::cout << shared_array[i] << "\n";
Once I got it to a point where it more-or-less worked, I noticed that the
output wasn’t quite right. The sorted array was correct in memory, but when I
redirected stdout into wc
to count the size of the output, it consistently
came up a little short.
For example, when sorting an array of 16,384 elements, the actual size of the output would be either 16,264 or 16,263, and occasionally the last number in the file would be missing digits (e.g., 4 instead of 499).
Being a C-guy (who begrudgingly is required to use C++), I added an fprintf
call to verify the number of elements actually being written,
for (int i = 0; i < ELEMENT_CNT; i++) {
std::cout << shared_array[i] << "\n";
fprintf(stderr, "%d\t%d\n", i, shared_array[i]);
}
and, lo and behold, they were all there!
At this point, I was reasonable sure that it was a buffer-related issue. It looked a lot like my output was being stuck in a buffer and then not flushed properly before the program terminated.
And that’s exactly what it was. As it turns out, the problem is that the
provided test code isn’t using std::cout
quite correctly.
std::endl
is something I’ve seen associated with most calls to std::cout
in
the wild, but I always assumed it was just a long way of saying, “put a newline
here” (like Environment.NewLine
in C#). Upon finally pulling up the
documentation on it, though, I found that there is an important difference.
std::endl
Inserts a new-line character, and flushes the stream 1
It would seem that data written to std::cout
isn’t necessarily flushed until an
std::endl
comes along.
Replacing the \n
from the test code with std::endl
, like so,
for (int i = 0; i < ELEMENT_CNT; i++)
std::cout << shared_array[i] << std::endl;
fixed the problem immediately and completely.
So, there you have it! If you’re going to use std::cout
in C++, you
definitely want to be using std::endl
rather than \n
. Personally, I’m
content (at least for now) to leave a #include <cstdio>
at the top of my C++
files, but even so, that was definitely a useful lesson to learn.