告诉`endl`不要冲洗

时间:2014-01-15 04:31:22

标签: c++ newline iostream

我的程序会将大量短行打印到cout

作为一个有点人为的例子,我的线条看起来有点像这样:

cout<<"The variable's value is: "<<variable<<endl;

我希望程序运行 fast 并且我确实认为endl正在杀死我,因为它每次使用时都会在cout上启动缓冲区刷新。

现在,互联网上的一些人说我可以这样做:

cout<<"The variable's value is: "<<variable<<"\n";

但这似乎不是一个好的解决方案,因为endl抽象出特定于系统的特定方式可以指定一个结束行,而\n则没有。这似乎也是一个糟糕的解决方案,因为如果我将来需要缓冲,那么我将不得不修改整个代码库。

因此,我问,有没有办法禁用endl的缓冲区刷新方面?

修改

进一步挖掘似乎表明endl\n都尊重操作系统可能选择结束它的各种方式。 It also seems输出流检测到它是否处于潜在的交互状态并相应地缓冲和刷新。因此:问题可以通过手动告诉输出流执行积极缓冲来解决......如果我能弄清楚如何做到这一点。

5 个答案:

答案 0 :(得分:8)

  

endl抽象特定系统特定的方式可以指定结束行,其中\ n不是“。

std::endl定义为输出'\n'后跟同花。正确抽象系统特定的换行符只是'\n'

为防止刷新,我们不会使用std::endl。此外,如果标准输出是或可能连接到交互设备,则标准输出可以是行缓冲的,在这种情况下,换行符将刷新流。如果这是一个问题,请使用连接到指定文件的ofstream。我认为在类Unix系统上,线路缓冲仅在标准输出是终端时发生。

答案 1 :(得分:5)

endl冲洗。如果您不想要这种行为,请不要使用endl。如果您想轻松更改代码,请使用自己的操作符:

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

通过这种方式,您可以轻松地在一个位置更改myendl的行为。

答案 2 :(得分:3)

根据http://en.cppreference.com/w/cpp/io/manip/endl

endl ::将一个endline字符插入到输出序列os中并将其刷新,就像调用os.put(os.widen('\n'))后跟os.flush()一样。

所以看起来你只想写os.put(os.widen('\n')),从这个定义来看,它应该是安全,可移植和正确的,并且满足你的主要需求。

答案 3 :(得分:1)

有std :: nounitbuf记录在这个问题上有一些影响。 但是,我没有发现任何差异。为了绕过所有ostream关于何时或何时不冲洗的想法,我尝试了这个:

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();

这将执行时间从约33秒提高到约25秒。

如果您的输出转到xterm,您的执行速度会受到xterm的滚动等工作的严格限制。如果您使用管道过滤掉不必要的行,您会看到速度急剧增加,例如

./program | grep -v "The variable"

答案 4 :(得分:1)

如果刷新是问题,您可以实现一个流缓冲区,它覆盖sync()成员函数,只有在您指定的情况下才刷新到外部设备。如果您打算在整个计划中更改这些首选项,它还有义务创建您自己的操纵器flush_on_endlnoflush_on_endl

#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;
}