2

I've heard that the following program isn't guaranteed to print the string on every platform and to actually do it you need to add \n to the end or flush the buffer by other means. Is that true or does the standard guarantee the expected output anyway?

#include <iostream>

int main() {
    std::cout << "Hello, world!";
}
Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
cppbest
  • 59
  • 8
  • 1
    Why worry? If you need to have this output guaranteed, just `std::flush` it and forget it. – Sam Varshavchik Oct 23 '22 at 17:46
  • `cout` is typically* line-buffered (* implementation-defined!), if so then it would usually need a line break or explicit flush, yes (unless the buffer fills up, then it is flushed). Though, the buffer should get flushed automatically on program exit – Remy Lebeau Oct 23 '22 at 17:46
  • Why minuses? Explain pls what I need to change. – cppbest Oct 23 '22 at 17:47
  • @RemyLebeau *should* or must? I.e. is it specified by the standard? – cppbest Oct 23 '22 at 17:48
  • @SamVarshavchik worry at least for educational purposes. – cppbest Oct 23 '22 at 17:49
  • 2
    @cppbest it is not *guaranteed*, no. In fact, one way it won't flush automatically at exit is if the process ends due to `std::terminate()` being called, unless you disable buffering or use `std::set_terminate()` to flush manually. See https://stackoverflow.com/questions/62326830/ – Remy Lebeau Oct 23 '22 at 17:53
  • 1
    @cppbest -- "should". Back in the olden days there were mainframe systems with record-oriented I/O systems, and it took great creativity to implement streaming I/O. Without a newline output would sometimes unavoidably fail, so the C (and by inheritance C++) standard allows the system to not output text that isn't followed by a newline. In practice this is not a significant issue today unless the program exits abnormally. – Pete Becker Oct 23 '22 at 17:53
  • "Why minuses?" - I think because you tagged language-lawyer and haven't made an attempt to look it up in the specification nor cite the specification. – Thomas Weller Oct 23 '22 at 17:59
  • It is guaranteed to print it, there's no guarantee however of when the string will appear on your terminal – Alan Birtles Oct 23 '22 at 18:00
  • @AlanBirtles can u prodive a link to the relevant paragraph in the standard? – cppbest Oct 23 '22 at 18:04
  • @ThomasWeller well, I tagged it so in order to find the relevant specification quote. – cppbest Oct 23 '22 at 18:05
  • 2
    Somehow, a question about the standard has not received a single response with a reference to the standard. – Alexander Guyer Oct 23 '22 at 18:07
  • 1
    @AlexanderGuyer: which is easily possible because the question is just 22 minutes old and finding a quote in the standard may easily take 2 hours. – Thomas Weller Oct 23 '22 at 18:08
  • `'\n'` doesn't flush a buffer, `std::endl` does. – Evg Oct 23 '22 at 18:15
  • @Evg in general, yes. But when `cout` is line-buffered (as it *usually* is in many implementations), then writing a `'\n'` does flush the buffer. But this is implementation defined behavior. – Remy Lebeau Oct 24 '22 at 01:28
  • @RemyLebeau Didn't know that, thanks. I should take a look at some implementation that does it. – Evg Oct 24 '22 at 02:47

1 Answers1

4

[ios.init]/1 The class Init describes an object whose construction ensures the construction of the eight objects declared in <iostream> (29.4) that associate file stream buffers with the standard C streams provided for by the functions declared in <cstdio> (29.12.1).

[ios.init]/3
Init();
Effects: Constructs and initializes the objects cin, cout, cerr, clog, wcin, wcout, wcerr, and wclog if they have not already been constructed and initialized.

[ios.init]/4
~Init();
Effects: If there are no other instances of the class still in existence, calls cout.flush(), cerr.flush(), clog.flush(), wcout.flush(), wcerr.flush(), wclog.flush().

So therefore, std::cout.flush() would be called as part of the program's normal termination sequence, by the destructor of the same object (sometimes known as nifty counter) that ensured std::cout was initialized in the first place.

Igor Tandetnik
  • 50,461
  • 4
  • 56
  • 85
  • "If there are no other instances of the class still in existence" — is it possible there **are** those instances? – cppbest Oct 24 '22 at 06:01
  • @cppbest: If you create them, then yes. More likely, if a library creates them. – MSalters Oct 24 '22 at 06:21
  • @MSalters does it mean that it's possible that `cout.flush()` will not be called and `\n` is required? – cppbest Oct 24 '22 at 06:25
  • 1
    @cppbest: In theory (if you allocate it on the heap). In practice, nobody does that, and global objects are all destroyed at program exit. – MSalters Oct 24 '22 at 06:34
  • 1
    There's a static variable of type `ios_base::Init` defined in every translation unit that includes . They are initialized in some unspecified order at the program startup, and destroyed at the program termination. They use a counter to figure out which one of them is the first to be initialized or the last to be destroyed. The first one to be initialized initializes `std::cout` et al; the last one to be destroyed calls `flush` on them. – Igor Tandetnik Oct 24 '22 at 13:26
  • 1
    This technique - again, sometimes referred to as "nifty counters" - guarantees that `std::cout` et al are available in constructors and destructors of global objects, and doesn't fall victim to the so-called [static initialization order fiasco](https://en.cppreference.com/w/cpp/language/siof) – Igor Tandetnik Oct 24 '22 at 13:28