Tell `endl` not to flush

馋奶兔 提交于 2019-12-08 18:35:29

endl abstracts the particular system-specific ways an end line might be specified, where as \n does not".

std::endl is defined to output '\n' followed by a flush. The correct abstraction of the system-specific newline thingy is just '\n'.

To prevent flushes, one just doesn't use std::endl. In addition, the standard output may be line-buffered if it is or may be connected to an interactive device, in this case the newline character will flush the stream. If that's an issue, use an ofstream connected to a named file. I think on Unix-like systems line buffering only happens when the standard output is a terminal.

endl flushes. If you don't want that behaviour, don't use endl. If you want to change your code easily, use your own manipulator:

inline std::ostream& myendl( std::ostream& os ){
    os.put(os.widen('\n'));
    return os;
}

That way you can easily change the behaviour of your myendl at one place.

According to http://en.cppreference.com/w/cpp/io/manip/endl

endl:: Inserts a endline character into the output sequence os and flushes it as if by calling os.put(os.widen('\n')) followed by os.flush().

So it appears you want to just write os.put(os.widen('\n')), which should, from this definition be safe and portable and correct, as well as meeting your primary needs.

There is std::nounitbuf which is documented to have some effect in this matter. However, I didn't notice any difference. To bypass all of the ostream's ideas of when or when not to flush I tried this:

std::ostringstream oss;
//  std::cout << std::nounitbuf;
for( int i = 0; i < 1000000; i++ ){
//  std::cout <<  "Test " << "file" << '\n';
    oss <<  "Test " << "file" << '\n';
}
std::cout << oss.str();

This improved execution time from ~33 sec to ~25csec.

IF your output goes to an xterm, your execution speed is severly limited by xterm's work to do scrolling etc. If you use a pipeline to filter out unnecessary lines you'll see a dramatic increase in speed, e.g.

./program | grep -v "The variable"

If flushing is the problem, you can implement a stream buffer that overrides the sync() member function to only flush to the external device if you specify so. It also obligates creating your own manipulators flush_on_endl and noflush_on_endl if you intend to change these preferences throughout the program.

#include <iostream>

static int disable() {
    static int index(std::ios_base::xalloc());
    return index;
}

class save_buffer
{
public:
    save_buffer(std::ios& other)
        : str(other), buf(other.rdbuf())
    { }

    ~save_buffer() { str.rdbuf(buf); }
private:
    std::ios& str;
    std::streambuf* buf;
};

class syncing_buffer_optional : public std::streambuf, private save_buffer
{
public:
    syncing_buffer_optional(std::ostream& other)
        : save_buffer(other),
          buf(other.rdbuf()),
          disable_sync(other.iword(disable()))
    { }

    std::streambuf::int_type overflow(std::streambuf::int_type c)
    {
        buf->sputc(c);
        return 0;
    }

    int sync()
    {
        return disable_sync? 0: buf->pubsync();
    }
private:
    std::streambuf* buf;
    bool disable_sync;
};

std::ostream& flush_on_endl(std::ostream& os)
{
    os.iword(disable()) = false;
    return os;
}

std::ostream& noflush_on_endl(std::ostream& os)
{
    os.iword(disable()) = true;
    return os;
}


std::ostream& endl(std::ostream& os)
{
    syncing_buffer_optional eb(os);
    os.rdbuf(&eb);

    return os << std::endl;
}

int main()
{
    std::cout << noflush_on_endl << endl;
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!