The statement on the learncpp.com
website is correct in principle, and your experimental results, while seemingly contradictory, can be explained by a technical detail of C++ streams and how they are typically configured.
The primary reason you observed std::cerr
to be faster than std::cout
is most likely due to a feature called synchronization with C standard I/O. By default, C++ streams (std::cout
, std::cin
, etc.) are synchronized with their C counterparts (stdout
, stdin
, etc.). This synchronization ensures that if you mix C and C++ I/O functions (e.g., printf
and std::cout
) in the same program, the output will appear in the correct order.
This synchronization, however, comes with a significant performance penalty. It effectively forces a flush of the std::cout
buffer after every operation to ensure all data is immediately written out. In this default configuration, std::cout
behaves more like std::cerr
in that it does not fully utilize its buffer for performance.
Since std::cerr
is an unbuffered stream by default and is not tied to stdout
in the same way, it bypasses this synchronization overhead, which is why it appeared faster in your tests.
The statement from learncpp.com
is based on the general principle of I/O buffering. When you disable the synchronization, std::cout
can buffer its output, allowing the operating system to write a large chunk of data to the console in a single, efficient operation, which is much faster than the numerous, individual write calls required by an unbuffered stream like std::cerr
.
For a program that performs a very large number of I/O operations, such as a competitive programming solution or a data processing script, you can dramatically increase the performance of std::cout
by adding the following line at the beginning of your main
function:
std::ios_base::sync_with_stdio(false);
This line disables the synchronization, allowing std::cout
to fully utilize its buffer and perform significantly faster than std::cerr
for bulk output.
Your program was not complex enough to demonstrate the full performance potential of std::cout
because the default synchronization setting was hindering its performance. The experiment you conducted highlights a common performance trap for C++ programmers who are new to the language.
C++ Weekly: Use cout
, cerr
, and clog
Correctly
This video explains the correct use of std::cout, std::cerr, and std::clog.