I'm timing the difference between various ways to print text to standard output. I'm testing cout
, printf
, and ostringstream
using both \n
and std::endl
. I expected std::endl
to make a difference with cout
(and it did), but I didn't expect it to slow down output with ostringstream
. I thought using std::endl
would just write a \n
to the stream and it would still only get flushed once. What's going on here? Here's all my code:
// cout.cpp
#include <iostream>
using namespace std;
int main() {
for (int i = 0; i < 10000000; i++) {
cout << "Hello World!\n";
}
return 0;
}
// printf.cpp
#include <stdio.h>
int main() {
for (int i = 0; i < 10000000; i++) {
printf("Hello World!\n");
}
return 0;
}
// stream.cpp
#include <iostream>
#include <sstream>
using namespace std;
int main () {
ostringstream ss;
for (int i = 0; i < 10000000; i++) {
ss << "stream" << endl;
}
cout << ss.str();
}
// streamn.cpp
#include <iostream>
#include <sstream>
using namespace std;
int main () {
ostringstream ss;
for (int i = 0; i < 10000000; i++) {
ss << "stream\n";
}
cout << ss.str();
}
And here's my Makefile
SHELL:=/bin/bash
all: cout.cpp printf.cpp
g++ cout.cpp -o cout.out
g++ printf.cpp -o printf.out
g++ stream.cpp -o stream.out
g++ streamn.cpp -o streamn.out
time:
time ./cout.out > output.txt
time ./printf.out > output.txt
time ./stream.out > output.txt
time ./streamn.out > output.txt
Here's what I get when I run make
followed by make time
time ./cout.out > output.txt
real 0m1.771s
user 0m0.616s
sys 0m0.148s
time ./printf.out > output.txt
real 0m2.411s
user 0m0.392s
sys 0m0.172s
time ./stream.out > output.txt
real 0m2.048s
user 0m0.632s
sys 0m0.220s
time ./streamn.out > output.txt
real 0m1.742s
user 0m0.404s
sys 0m0.200s
These results are consistent.
Use of std::endl in place of '\n', encouraged by some sources, may significantly degrade output performance.
Both endl and \n serve the same purpose in C++ – they insert a new line. However, the key difference between them is that endl causes a flushing of the output buffer every time it is called, whereas \n does not.
There is rarely a need for std::endl , and getting in the habit of using it will lead to mysteriously slow code. Just use '\n' unless you know you need to flush the buffer.
std::endl writes a newline to the output stream and flushes it.
std::endl
triggers a flush of the stream, which slows down printing a lot. See http://en.cppreference.com/w/cpp/io/manip/endl
It is often recommended to not use std::endl
unless you really want the stream to be flushed. If this is really important to you, depends on your use case.
Regarding why flush
has a performance impact even on a ostringstream (where no flushing should happen): It seems that an implementation is required to at least construct the sentry objects. Those need to check good
and tie
of the ostream
. The call to pubsync
should be able to be optimized out. This is based on my reading of libcpp and libstdc++.
After some more reading the interesting question seems to be this: Is an implementation of basic_ostringstream::flush
really required to construct the sentry object? If not, this seems like a "quality of implementation" issues to me. But I actually think it needs to because even a basic_stringbug
can change to have its badbit
set.
Each output operation on a stream dors multiple steps:
endl
calls an extra virtual function on the stream buffer.I would personally expect that the extra virtual function call actually has relativly small impact compared to the other operations. You can verify this guess by also profiling this output:
out << "stream" << '\n';
... or even
out << "stream" << out.widen('\n');
That said, there are a number of improvements which a stream implementation can apply to cut down on checks. Whether this is done will depend on the implementation, of course.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With