Many C++ text books advertise the use of std::endl
to terminate lines when writing to an std::ostream
. Unfortunately, it seems that few people understand what std::endl
does or if they know they underestimate the impact. What most people don’t notice is that std::endl
does two things: it inserts a newline character i.e. '\n'
and then it flushes the std::ostream
. It is this extra flush which makes the operation quite expensive. Here is a very simple example program demonstrating the difference:
#include <fstream> #include <string> template <typename cT, typename Traits> std::basic_ostream<cT, Traits>& nl(std::basic_ostream<cT, Traits>& out) { return out << out.widen('\n'); } int main(int ac, char*[]) { std::string text("0123456789012345678901234567890123456789"); std::ostream& (*end)(std::ostream&) = std::endl; if (ac == 1) end = ::nl; std::ofstream out("file.txt", std::ios_base::binary); for (size_t i(0); i != 1000000; ++i) { out << text << text << end; } }
All this program does is to write a million lines of 80 characters plus a newline. Depending on whether the program received a command line parameter it either uses std::endl
or the custom manipulator ::nl
to terminate lines. To make a fair comparison ::nl
is implement like std::endl
i.e. as a function template. Since the character type isn’t known, it needs to widen the newline character '\n'
. Running this program on my machine shows a factor of about 6 between the time the programs take! The version using endl
take a bit more than 3 second while the version using ::nl
only take about 0.5 seconds.
This extra flushing the stream causes the file to write each block multiple times instead of just once when the buffer has become full. This easily slows down I/O intensive operations and my cause a bottleneck. Thus, don’t use std::endl
unless the flush is actually intentional. Also note that std::cerr
is already setup to flush the stream after every individual output operation. This is done using the flag std::ios_bse::unitbuf
which is initially set for std::cerr
. To turn this off you can use the formatter std::nounitbuf
and to turn it on you would use std::unitbuf
.