10

I stumbled upon a question in Codereview, and in one answer the feedback was to avoid std::endl because it flushes the stream. The full quote is:

I'd advise avoiding std::endl in general. Along with writing a new-line to the stream, it flushes the stream. You want the new-line, but almost never want to flush the stream, so it's generally better to just write a \n. On the rare occasion that you actually want the flush, do it explicitly: std::cout << '\n' << std::flush;.

The poster did not explain this, neither in the post or comments. So my question is simply this:

Why do you want to avoid flushing?

What made me even more curious was that the poster says that it's very rare that you want to flush. I have no problem imagining situations where you want to avoid flushing, but I still thought that you in general would want to flush when you print a newline. After all, isn't that the reason why std::endl is flushing in the first place?

Just to comment the close votes in advance:

I do not consider this opinion based. Which you should prefer may be opinion based but there are objective reasons to take into account. The answers so far proves this. Flushing affects performance.

klutt
  • 1,428
  • 1
  • 10
  • 25
  • see [Discuss this ${blog}](https://softwareengineering.meta.stackexchange.com/a/6418/31260) – gnat Jan 29 '19 at 12:00
  • 1
    @gnat Well, I'm not looking for the ultimate answer to the question wether I should flush or not. That's subjective. But I'm pretty sure there are some objective pros and cons. – klutt Jan 29 '19 at 12:06
  • https://stackoverflow.com/questions/213907/c-stdendl-vs-n – Martin Ba Jan 29 '19 at 12:07
  • @MartinBa The answers there basically says that the difference between `\n` and `std::endl` is that the latter flushes, but does not explain the pros and cons. – klutt Jan 29 '19 at 12:23
  • 1
    https://stackoverflow.com/questions/17370093/should-c-programmers-use-stdflush-frequently?lq=1 –  Jan 29 '19 at 12:34
  • https://en.cppreference.com/w/cpp/io/manip/endl – Mat Jan 29 '19 at 12:57
  • https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#slio50-avoid-endl – Mat Jan 29 '19 at 12:59

3 Answers3

14

Each time a process produces output, it has to call a function that actually does the work. In most cases, that function is ultimately write(2). On a multitasking operating system, the call to write() will trap into the kernel, which has to stop the process, handle the I/O, do other things while any blockages are cleared, put it on the ready queue and get it running again when the time comes. Collectively, you can call all of that activity system call overhead. If that sounds like a lot, it is.

Flushing a buffered stream* after writing a small amount of data or having no buffer at all incurs that overhead each time you do it:

1\n  (System call that writes two bytes)
2\n  (System call that writes two bytes)
3\n  (System call that writes two bytes)
4\n  (System call that writes two bytes)
5\n  (System call that writes two bytes)

This is how it was done in the very early days until someone figured out that it was burning a lot of system time. The overhead could be kept down by by accumulating output in a buffer until it was full or the program decided that it must be sent immediately. (You might want to do the latter if you're producing output sporadically that needs to be seen or consumed.) Avoiding a flush at the end of each line cuts the number of system calls, and the overhead incurred:

1\n
2\n
3\n
4\n
5\n  (Flush) (System call that writes ten bytes)

*Note that the concept of standard output is a file descriptor associated with a process and given a well-known number. This differs from the stdout defined by C, C++ and others, which are identifiers for implementations of a buffered stream that live entirely in userland and write to the standard output. The write() system call is not buffered.

Blrfl
  • 20,235
  • 2
  • 49
  • 75
  • 3
    Whether and when to flush depends on the context in which that output will be used. A throughput-oriented program should only flush when its buffers are full. A latency-sensitive program should flush more often. E.g. if the output goes to a console, you would still flush after each newline. Interactive programs (that show some input prompt) should flush immediately, even if the line is not yet full. – amon Jan 29 '19 at 13:23
  • "if the output goes to a console, you would still flush after each newline." True, but if the output goes to a console, there is an automatic flush after each newline. No need to do that explicitly. – Roel Schroeven Jan 29 '19 at 14:44
  • 1
    @amon You would still want to coalesce consecutive output, as flushing timely, meaning before asking for input and without overdue delay, is plenty sufficient. Admittedly, it is better to flush once too often than have too much delay in showing the output, or investing too much work in optimising... – Deduplicator Jan 29 '19 at 17:14
  • One trick sometimes used by the bufferers is to re/start a timer when new stuff comes, and flush when the timer runs out. – John Dvorak Jan 29 '19 at 18:30
7

The short and simple answer is that using std::endl can and will slow output by a huge margin. In fact, I'm reasonably convinced that std::endl is responsible for most of the notion that C++ iostreams are substantially slower than C-style I/O.

For example, consider a program like this:

#include <iostream>
#include <string>
#include <sstream>
#include <time.h>
#include <iomanip>
#include <algorithm>
#include <iterator>
#include <stdio.h>

char fmt[] = "%s\n";
static const int count = 3000000;
static char const *const string = "This is a string.";
static std::string s = std::string(string) + "\n";

void show_time(void (*f)(), char const *caption) { 
    clock_t start = clock();
    f();
    clock_t ticks = clock()-start;
    std::cerr << std::setw(30) << caption 
        << ": " 
        << (double)ticks/CLOCKS_PER_SEC << "\n";
}

void use_printf() {
    for (int i=0; i<count; i++)
        printf(fmt, string);
}

void use_puts() {
    for (int i=0; i<count; i++) 
        puts(string);        
}

void use_cout() { 
    for (int i=0; i<count; i++)
        std::cout << string << "\n";
}

void use_cout_unsync() { 
    std::cout.sync_with_stdio(false);
    for (int i=0; i<count; i++)
        std::cout << string << "\n";
    std::cout.sync_with_stdio(true);
}

void use_stringstream() { 
    std::stringstream temp;
    for (int i=0; i<count; i++)
        temp << string << "\n";
    std::cout << temp.str();
}

void use_endl() { 
    for (int i=0; i<count; i++)
        std::cout << string << std::endl;
}

void use_fill_n() { 
    std::fill_n(std::ostream_iterator<char const *>(std::cout, "\n"), count, string);
}

void use_write() {
    for (int i = 0; i < count; i++)
        std::cout.write(s.data(), s.size());
}

int main() { 
    show_time(use_printf, "Time using printf");
    show_time(use_puts, "Time using puts");
    show_time(use_cout, "Time using cout (synced)");
    show_time(use_cout_unsync, "Time using cout (un-synced)");
    show_time(use_stringstream, "Time using stringstream");
    show_time(use_endl, "Time using endl");
    show_time(use_fill_n, "Time using fill_n");
    show_time(use_write, "Time using write");
    return 0;
}

With standard output redirected to a file, this produces the following results:

             Time using printf: 0.208539
               Time using puts: 0.103065
      Time using cout (synced): 0.241377
   Time using cout (un-synced): 0.181853
       Time using stringstream: 0.223617
               Time using endl: 4.32881
             Time using fill_n: 0.209951
              Time using write: 0.102781

Using std::endl slowed the program by a factor of about 20 in this case. If you wrote shorter strings, the slow-down could/would be even greater.

There are a few cases where you really and truly do want to flush a stream manually--but they honestly are pretty few and far between.

Most times a stream needs to be flushed (e.g., you print a prompt, then wait for some input) it'll happen automatically unless you've used things like std::tie and/or std::sync_with_stdio to prevent that.

That leaves only a tiny number of truly unusual situations where you have good reason to flush a stream manually. Such cases are rare enough that it's well worth using std::flush when they happen, to make it apparent to the anybody reading the code that you're flushing the stream intentionally (and more often than not, probably also merits a comment about why this is one of the rare cases when flushing the stream really makes sense).

Jerry Coffin
  • 44,385
  • 5
  • 89
  • 162
1

Why flush is to be avoided:

Because IO works best when the operating system can work with relatively large amounts of data. Regular flushes with small amounts of data cause slowdowns, sometimes very significantly.

Why you should almost never flush manually:

There are automatic flushes that cover most use cases. For example, if a program writes to the console, the system by default flushes after every newline. Or if you write to file, the data is written once there is enough data to be written at once, and also when the file is closed.

When you should flush manually:

If you explicitly need to update the output immediately. Example: if you create a spinner or progress bar that repeatedly overwrites the current line. Or if you output to file and really want the file to be updated at specific moments.

Roel Schroeven
  • 268
  • 1
  • 6
  • The system cannot flush any user-buffers. Or do you subsume libraries, especially the standard library, also under "system"? Of course, `stdin` and `stdout` are generally coupled at least if they both use the same console. – Deduplicator Jan 29 '19 at 17:17
  • Yes, I didn't think it would be a good idea to go into too much detail about how things are split between userspace libraries and kernel space. – Roel Schroeven Jan 29 '19 at 20:54