13

In an effort to better understand buffered streams in C++, I would like to write a simple program in which the std::cout buffer is NOT flushed before termination. Since I have read that std::cout is flushed on normal termination, I tried throwing a runtime error. I also avoided using std::endl, as I understand that forces a flush. First attempt:

//file noflush.cpp
#include <iostream>

int main() {
    std::cout << "Don't write me to the console!";
    throw 0;
}

Compile with g++, call from terminal:

$ ./noflush
libc++abi.dylib: terminating with uncaught exception of type int
Don't write me to the console!Abort trap: 6

Even when I force a runtime error, it seems the buffer still gets flushed on termination. Is it possible to "strand" some data in the buffer, leaving it unwritten to the device?

Walter
  • 44,150
  • 20
  • 113
  • 196
ivme
  • 548
  • 5
  • 14
  • Just to say that even when aborting with `std::abort()` the buffer is flushed, (using Apple LLVM version 6.0 (clang-600.0.57) (based on LLVM 3.5svn) with LLVM libc++), though according to [cppreference](http://en.cppreference.com/w/cpp/utility/program/abort) it is implementation defined *whether open resources such as files are closed* (upon calling `std::abort()`). – Walter Jun 01 '16 at 08:11

5 Answers5

10

This is not standard c++, but in POSIX, you can send a "kill" signal to kill the running process. This will stop the execution without cleanup such as flushing buffers.

Edit: I realized that signals are not only POSIX but actually part of C standard library (and included in the C++ standard library).

#include <csignal>
// ...
std::cout << "Don't write me to the console!";
std::raise(SIGKILL);
eerorika
  • 232,697
  • 12
  • 197
  • 326
  • How about dereference null pointer to induce null pointer exception / runtime seg faul? That might be a good cross-platform way to kill a process. – kevinarpe Jun 01 '16 at 09:31
  • @kevinarpe dereferencing a null pointer has undefined behaviour, so it's not guaranteed to kill the process and isn't portable technically... In practice though, *crash on null pointer dereference* might be more widely "supported" than POSIX. That's basically same suggestion as Caduchon's answer, except the UB from null pointer dereference is probably more consistent than UB from dereferencing and deleting an uninitialized pointer. – eerorika Jun 01 '16 at 09:50
  • 1
    @kevinarpe Crashing on dereferencing a null pointer is not guaranteed. – Leandros Jun 01 '16 at 09:59
  • @Leandros I suspect the non-flushing of buffers on SIGKILL is also not guaranteed. Or even the existence of SIGKILL. – user253751 Jun 01 '16 at 12:37
  • 1
    @immibis It is guaranteed by the semantics of SIGKILL. Programs cannot handle SIGKILL and so cannot run cleanup code in response to it. – John Kugelman Jun 01 '16 at 14:59
9

As far as I can tell, there is no standard compliant and clean way to avoid std::cout to flush() before program termination (but, of course, you can use unclean methods, e.g. raising a signal either directly or indirectly). According to cppreference, the actual buffer type controlled by std::cout is implementation defined but derived from std::streambuf, which does not appear to allow public access in a way that would emulate silent swallowing of the buffer.

Further, as I noted in a comment, even abnormal program termination (via std::terminate() or std::abort() may or may not close open resources, so this is again implementation defined.

Community
  • 1
  • 1
Walter
  • 44,150
  • 20
  • 113
  • 196
  • The correct quote is "The global objects std::cout [...] control output to a stream buffer of implementation-defined type [...]" (The buffer and not the stream object is implementation defined) –  Jun 01 '16 at 20:05
4

With the following example, I can create the behaviour you want with gcc 4.8.3 :

#include <iostream>
#include <vector>

int main()
{
    std::string str;
    for(unsigned long int i = 0; i < 10000; ++i)
        str += "Hello ! ";
    str += "END";
    std::cout << str;

    std::vector<double>* p;
    p->push_back(1.0);
    delete p;

    std::cout << "STILL ALIVE !" << std::endl;

    return 0;
}

Then, the output is :

Hello ! Hello ! Hello ! Hello ! Hello ! Hello ! Hello ! Hello ! Hello ! Hello ! Hello ! Hello ! Hello ! Hello ! Hello ! Hello ! Hello ! Hello ! Hello ! Hello ! Hello ! Hello ! Hello ! Hello ! Hello ! Hello ! Hello ! Hello ! Hello ! Hello ! Hello ! Hello ! Hello ! Hello ! Hello ! Hello ! Hello ! Hello ! Hello ! Hello ! Hello ! Hello ! Hello ! Hello ! Hello ! Hello ! [...] Hello ! Segmentation fault

We can see than END is not printed before the segmentation fault.

Caduchon
  • 4,574
  • 4
  • 26
  • 67
  • Uhmm... does the example work even with 10 instead of 10000 in the loop? – Alessandro Teruzzi Jun 01 '16 at 09:08
  • 1
    When I tried with 10, the segmentation fault was immediate. Thus yes, it also works, but more fuzzily. – Caduchon Jun 01 '16 at 09:10
  • the initial code does NOT show the behaviour OP is looking for, because the program crash before even putting "STILL ALIVE !" in the buffer, while with 10 instead of 10000 it crashes without displaying anything, while the Hello! ARE in the buffer : this is the bahaviour expected – Guiroux Jun 01 '16 at 09:26
  • 2
    No, the end of the string is `"END"`. It's not printed. Then the string is partially printed. The buffer is not flusshed correclty. I don't understand you put -1 for that ! – Caduchon Jun 01 '16 at 09:34
  • My bad, i didn't look the program answer till this end, still, why did you did a loop, and why the `std::cout << "STILL ALIVE !" << std::endl;` they both draw away from the point. A simple cout before the intentionnal crash would have been clearer, and btw, don't assume everybody on the internet is an asshole, i just wanted you to make your answer a little more simple and to the point, I didn't -1 you, DON'T assume things you just don't know about what others did. – Guiroux Jun 01 '16 at 09:46
  • 1
    The loop is for the creation of a big string : better to see buffer problems occur. The "END" for simply check all the string is printed. "STILL ALIVE" because a segmentation fault is not always throwed (as example, if you access to your own memory, typically a growing buffer). Stay calm ! The -1 and your comment happened in the same time, and comment a -1 is a good practice. It was normal I assumed it was you... – Caduchon Jun 01 '16 at 09:53
  • 2
    @Caduchon still, it's polite to give the commenters the benefit of doubt. They're trying to help after all and unfortunately this site has plenty of downvote ninjas who don't bother justifying their votes. P.S. I'm sorry for going totally off topic. – eerorika Jun 01 '16 at 10:07
  • Apologizes if I seem unpolite. I don't quite agree with `The loop is for the creation of a big string : better to see buffer problems occur`, because the loop is more than anything showing that the buffer regularly get flushed when being filled, which is not really the question, but related and interesting I admit. For the fact that segfault don't always happens, it's an undefined behaviour not at all linked with the problem, so you could just set explicity the pointer to not accessible memory – Guiroux Jun 01 '16 at 12:18
0

If I get you right, you want to capture or ignore the output to std::cout:

#include <iostream>
#include <sstream>
int main()
{
    // Capture the output to `std::cout`
    {
        std::cout << "[Capture Output]" << std::endl;
        std::stringstream cpature;
        auto restore = std::cout.rdbuf(cpature.rdbuf());

        std::cout << "... captured output ..." << std::endl;

        std::cout.rdbuf(restore);
        std::cout << "[Enable Output]" << std::endl;

        // Display the cpatured output.
        std::cout << cpature.rdbuf();
    }
    std::cout << std::endl;

    // Even more drasticly: Ignore the output to `std::cout`
    {
        std::cout << "[Ignore Output]" << std::endl;
        auto restore = std::cout.rdbuf(nullptr);

        std::cout << "... ignored output ..." << std::endl;

        std::cout.rdbuf(restore);
        std::cout << "[Enable Output]" << std::endl;
    }

    std::cout << "[End]\n";
}
0
#include <iostream>
#include <sstream>
#include <vector>
int main()
{
    std::stringstream cpature;
    auto restore = std::cout.rdbuf(cpature.rdbuf());    
    std::cout.rdbuf(restore);
    for(unsigned long int i = 0; i < 10000; ++i)
        std::cout <<"Hello ! "  << std::endl;
    std::cout << "END"  << std::endl;

    std::cout << cpature.rdbuf();
    std::vector<double> *p;
    p->push_back(1.0);
    delete p;
    std::cout << "STILL ALIVE !" << std::endl;
}