std::cout << std::endl is not always faster than std::cout << “\n”

Performance depends on the underlying stream buffer.

std::endl writes a newline to the output stream and flushes it. In most cases, the developer doesn’t need to flush. Flushing operation is expensive, because it involves a system call. Instead of std::endl, you can simply write “\n”. Then the content will be flushed if the content size is more than the buffer size or the application closes.

But this is always not true.

For a program, three text streams are always provided.

  1. standard input
  2. standard output
  3. standard error

Both standard input and standard output are fully buffered. Standard error is line buffered.

For fully buffered stream, characters are accumulated and transferred as a block. The buffer will be flushed when

  • The buffer is full.
  • The stream is closed.
  • If the main function returns or exits without an error(normal termination), buffers associated with all opened files are flushed.
  • The stream is bidirectional and application tries to read just after writing.

For an unbuffered stream, characters are transferred as soon as possible.

For a line buffered stream, characters are accumulated and transferred when it sees a new line. In an application, error streams are usually line buffered. In C++, std::cerr is line buffered.

If there is an interactive device associated with the application, then the streams are line buffered. Here the interactive device means, the application writes to a console.

Behavior of std::cout(c++ standard output stream) depends on whether the stream is line-buffered or buffered.

#include <iostream>int main()
{
for (char i='A'; i <= 'E'; i++) {
std::cout << i << '\n';
}
return 0;
}

We can use strace to look at the system calls.

strace ./main_newline

The file descriptor of the output stream is 1. We can check the system calls which starts with write(1,.

write(1, "A\n", 2)                      = 2
write(1, "B\n", 2) = 2
write(1, "C\n", 2) = 2
write(1, "D\n", 2) = 2
write(1, "E\n", 2) = 2

There is a flush after every ‘\n’.

We can run the same program by redirecting the output to a filed(so that it won’t have an attached interactive device).

strace ./main_newline > op.txtwrite(1, “A\nB\nC\nD\nE\n”, 10) = 10

There is only 1 flush, with all characters accumulated as one block.

We can write the same program with ‘\n’ replaced with std::endl and check the system call traces.

#include <iostream>int main()
{
for (char i='A'; i <= 'E'; i++) {
std::cout << i << std::endl;
}
return 0;
}
write(1, “A\n”, 2) = 2
write(1, “B\n”, 2) = 2
write(1, “C\n”, 2) = 2
write(1, “D\n”, 2) = 2
write(1, “E\n”, 2) = 2

By the std::endl specification, it will always add a ‘\n’ and flush the output. And our program does the exact the same thing, flushes after every std::endl call.

We can conclude the following things

For an application with an attached interactive device, std::cout will always flush after it sees the newline character. So, both std::endl and ‘\n’ will do the same.

For an application with no attached interactive device, std::cout will flush only in case of std::endl. ‘\n’ will give performance benefit.

Thanks for reading !!

Reference: https://www.gnu.org/software/libc/manual/html_node/Buffering-Concepts.html

C++11/14, Qt, Juce

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store