Introduction: the war of two characters
If you've ever written in C++ and output text to the console, you've definitely faced the dilemma: use std::endl or ""? At first glance, the difference is minimal — both create a new line. But behind this simple choice lies a whole story about performance, buffering, and unexpected slowdowns in your program.
On Stack Overflow, this question has garnered thousands of views and sparked heated debates. Today we'll settle this topic once and for all: which is faster, why, and when each option is justified. If you write in C++ and want your code to run as efficiently as possible — this article is for you.
The short answer (spoiler)
"" is always faster than std::endl. But not because std::endl is slow in itself, but because it does extra work. std::endl doesn't just add a newline character — it also flushes the output buffer. And this is an operation that can cost you precious milliseconds.
Let's break down what this means in practice and look at the code.
How output works in C++
When you write std::cout << "Hello";, the data isn't sent to the screen immediately. It accumulates in a buffer — a temporary storage area in memory. This is done for efficiency: sending data one character at a time to the screen is too slow, so the system waits until enough data has accumulated and sends it all in one batch.
Flushing the buffer is a forced sending of all accumulated data. This is exactly what std::endl does.
What happens under the hood?
// Using std::endlstd::cout << "Line 1" << std::endl;// Equivalent to:std::cout << "Line 1" << '' << std::flush;
// Using ""std::cout << "Line 1";// Simply adds a newline character to the bufferSee the difference? std::endl does two actions: adds '' and calls std::flush. "" does only one.
Experiment: measuring performance
Let's test this with a real example. We'll write a small program that outputs 100,000 lines in two ways and measures the time.
#include <iostream>#include <chrono>
int main() { const int N = 100000; // Test with std::endl auto start = std::chrono::high_resolution_clock::now(); for (int i = 0; i < N; ++i) { std::cout << "Line number " << i << std::endl; } auto end = std::chrono::high_resolution_clock::now(); auto duration_endl = std::chrono::duration_cast<std::chrono::milliseconds>(end - start); std::cout << "Time with endl: " << duration_endl.count() << " ms"; // Test with "" start = std::chrono::high_resolution_clock::now(); for (int i = 0; i < N; ++i) { std::cout << "Line number " << i << ""; } end = std::chrono::high_resolution_clock::now(); auto duration_n = std::chrono::duration_cast<std::chrono::milliseconds>(end - start); std::cout << "Time with \\: " << duration_n.count() << " ms"; return 0;}Result (typical):
std::endl: ~350-400 ms"": ~5-10 ms
The difference is 30-70 times! And that's no joke. Each call to std::endl forces the system to contact the operating system to flush the buffer. And that's a system call, which is relatively expensive.
When is flush necessary?
But don't rush to completely abandon std::endl. Sometimes flushing the buffer is critical