【问题标题】:Is there a null std::ostream implementation in C++ or libraries?C++ 或库中是否有空 std::ostream 实现?
【发布时间】:2012-01-04 20:04:57
【问题描述】:

我正在寻找类似于/dev/nullstd::ostream 实现。它只会忽略流向它的任何内容。标准库或 Boost 中是否存在这样的东西?还是我必须自己动手?

【问题讨论】:

  • 你可以打开/dev/null变成std::ofstream
  • 需要一些便携的东西,@Alexandre
  • 我发现(否则这将是一个答案)stackoverflow.com/questions/313111/dev-null-in-windows 应该涵盖足够的案例。
  • 将 nullptr 传递给 std::ostream 怎么样?
  • @Myon 你不能那样做。

标签: c++ null ostream


【解决方案1】:

如果您有 boost,那么 boost/iostreams/device/null.hpp 中有一个 null ostream 和 istream 实现。要点:

#include "boost/iostreams/stream.hpp"
#include "boost/iostreams/device/null.hpp"
...
boost::iostreams::stream< boost::iostreams::null_sink > nullOstream( ( boost::iostreams::null_sink() ) );
...

【讨论】:

【解决方案2】:

最简单的解决方案就是使用未打开的std::ofstream。这 将导致流中的错误状态,但大多数输出​​器不会 检查这个;通常的习惯用法是将支票留到最后,在 关闭(这会将其放入您编写的代码中,您知道 流应该是无效的)。

否则,实现起来非常简单:只需创建一个 streambuf 包含一个小缓冲区,并将其设置在 overflow (总是返回成功)。请注意,这将比 但是,未打开的文件;各种&gt;&gt; 运营商仍将 转换(如果流有错误状态,他们不会这样做)。

编辑:

class NulStreambuf : public std::streambuf
{
    char                dummyBuffer[ 64 ];
protected:
    virtual int         overflow( int c ) 
    {
        setp( dummyBuffer, dummyBuffer + sizeof( dummyBuffer ) );
        return (c == traits_type::eof()) ? '\0' : c;
    }
};

通常提供一个派生自istream 的便利类 或ostream 也将包含此实例 它使用的缓冲区。大致如下:

class NulOStream : private NulStreambuf, public std::ostream
{
public:
    NulOStream() : std::ostream( this ) {}
    NulStreambuf* rdbuf() const { return this; }
};

或者你可以只使用std::ostream,传递地址 它的streambuf。

【讨论】:

  • 最初的想法(未开封std::ofstream)真的很酷。它是否可靠/符合标准,并且将来不太可能引起问题(异常?)?我有点担心性能,但我想唯一的浪费是调用 &lt;&lt; 运算符,检查一个 if 并返回?
  • @TomaszGandor:“它是否可靠/符合标准,并且将来不太可能导致问题(异常?)?” Well, sometimes..
【解决方案3】:

如果您在流上设置badbit,它将不会输出任何内容:

#include <iostream>

int main() {
    std::cout << "a\n";

    std::cout.setstate(std::ios_base::badbit);
    std::cout << "b\n";

    std::cout.clear();
    std::cout << "c\n";
}

输出:

a
c

【讨论】:

  • @MatthieuM。使用std::cout &lt;&lt; std::boolalpha 也是对全局变量的修改。也使用std::cout &lt;&lt; anything。我不明白你的意思。
  • 虽然你是对的,但在一般情况下,如果同一程序的一个或两个部分更改std::cout 的配置,则它们之间存在利益冲突。但是为什么它是可配置的呢?如果我在过去设计 C++,我会将输出过滤与输出流分开,例如 std::out_filter of; of &lt;&lt; std::boolalpha &lt;&lt; std::whatever_option; std::out_proxy(std::cout, of) &lt;&lt; "something";
  • @Notinlist:关于ostream的设计,我有很多whys;那时是早期的 C++,全局变量仍然很常见,经验也很少,它表明......我觉得将格式和输出位置混为一谈很尴尬,例如,我觉得 inject 格式化程序到流中,而不是使用 Decorator 模式等......但我有事后诸葛亮的好处。
【解决方案4】:

我知道这是一个非常古老的线程,但我想将此添加给任何正在寻找相同解决方案但没有提升和最快解决方案的人。

我结合了上面三个不同的建议,一个直接写入/dev/null(所以它涉及内核。)

令人惊讶的是,得票最多的 NullStream 表现最差。

以下是 100,000,000 次写入的结果:

a) /dev/null : 30 seconds
b) NullStream: 50 seconds
c) badbit    : 16 seconds (the winner in speed, but cannot test for errors!)
d) boost     : 25 seconds (the ultimate winner)

这是测试代码

#include <iostream>
#include <fstream>
#include <time.h>
#include <boost/iostreams/stream.hpp>

class NullStream : public std::ostream {
    class NullBuffer : public std::streambuf {
    public:
        int overflow( int c ) { return c; }
    } m_nb;
public:
    NullStream() : std::ostream( &m_nb ) {}
};

int test( std::ostream& ofs, const char* who ) {
    const time_t t = time(NULL);
    for ( int i = 0 ; i < 1000000000 ; i++ )
        ofs << "Say the same" ;
    std::cout << who << ": " << time(NULL) - t << std::endl;
}

void devnull() {
    std::ofstream ofs;
    ofs.open( "/dev/null", std::ofstream::out | std::ofstream::app );
    test(ofs, __FUNCTION__);
    ofs.close();
}

void nullstream() {
    NullStream ofs;
    test(ofs, __FUNCTION__);
}

void badbit() {
    std::ofstream ofs;
    ofs.setstate(std::ios_base::badbit);
    test(ofs, __FUNCTION__);
}

void boostnull() {
    boost::iostreams::stream< boost::iostreams::null_sink > nullOstream( ( boost::iostreams::null_sink() ) );
    test(nullOstream, __FUNCTION__);
}

int main() {
    devnull();
    nullstream();
    badbit();
    boostnull();
    return 0;
}

编辑

最快的解决方案 - 我们使用 badbit - 有一个缺点。如果程序检查输出是否成功写入——我不知道为什么程序不应该这样做——那么它会因为这个坏位而失败。 因此,亚军 - boost - 就是胜利者。

【讨论】:

  • 我认为 /dev/null 不能移植到 Windows。我尝试了 ofs.open("") 并且它没有写入任何文件,所以也许这是一个更好的选择?
  • @Eyal - 我专注于 /dev/null ,因为它在问题的对象中。我相信 Windows 中存在“nil”,但从开发的角度来看,我不知道如何使用它...
  • 在 Windows 上是“nul”:stackoverflow.com/questions/313111/…
【解决方案5】:

按照@user5406764 的回答,可以通过重载全局&lt;&lt; 运算符来跳过任何实际操作。解决方案应该是跨平台且最快的。

#include <iostream>

class NullStream : public std::ostream {
public:
  NullStream() : std::ostream(nullptr) {}
  NullStream(const NullStream &) : std::ostream(nullptr) {}
};

template <class T>
const NullStream &operator<<(NullStream &&os, const T &value) { 
  return os;
}

int main() {
  auto null = NullStream();
  std::cerr << "a" << std::endl;
  null << "b" << std::endl;
  std::cerr << "c" << std::endl;
}

输出:

a
c

【讨论】:

    【解决方案6】:

    您可以在没有第三方库的情况下做到这一点。只需使用rdbuf 将关联的流缓冲区设置为nullptr,您的工作就完成了

    std::cout << "Hello,";
    std::cout.rdbuf(nullptr);
    std::cout << " world!\n";
    

    在线示例here.

    【讨论】:

    • 这很好。但是只需要注意和badbit一样的问题仍然存在:使用rdbuf时,如果流缓冲区为空指针,函数会自动设置badbit错误状态标志(如果成员异常已经通过badbit可能会抛出异常)。 [cplusplus.com/reference/ios/ios/rdbuf/]
    【解决方案7】:
    struct NullStream // only subclass std::stream if you must
    {
        template<typename T>
        NullStream& operator<<(T const&) { return *this; }
    };
    
    NullStream TheNullStream; // There's your global instance
    

    【讨论】:

    • 请编辑您的答案并通过解释您的答案如何解决问题来添加一些上下文,而不是发布仅代码的答案。 From Review
    • 我一直在尝试制定这样的解决方案,以便优化器可以消除非调试版本中的调试日志记录。不幸的是,此处显示的流插入操作符模板与 std::endl 等操作符不匹配。
    【解决方案8】:

    对我来说,最简单的方法是:

    #include <fstream>
    
    std::ostream* out = &std::cout;
    
    std::ostream* nullstream() {
        static std::ofstream os;
        if (!os.is_open())
            os.open("/dev/null", std::ofstream::out | std::ofstream::app);
        return &os;
    }
    
    int main() {
        *out << "Normal output\n";
    
        out = nullstream();
        *out << "Will not visible\n";
    
        out = &std::cout;
        *out << "Back again\n";
    
        return 0;
    }
    

    或者如上所述在“nullstream”函数中使用“badbit”标志而不是“/dev/null”。

    std::ostream* nullstream() {
        static std::ofstream os;
        static bool flag_set = false;
        if (!flag_set) {
            os.setstate(std::ios_base::badbit);
            flag_set = true;
        }
        return &os;
    }
    

    【讨论】:

      【解决方案9】:

      此解决方案能否在不使用 boost 的情况下克服性能问题:

      #include <ostream>
      
      class dev0_buffer : public std::streambuf
      {
         //called usually for n-characters
         std::streamsize xsputn (const char* s, std::streamsize n) override { return n; }
      
         //may not required due it's not called anymore
         int overflow (int c)  override { return c; } 
      } nirwana;
      
      class dev0_stream : public std::ostream
      {
         public:
          dev0_stream(): std::ostream(&nirwana){}
      };
      

      【讨论】:

        猜你喜欢
        • 2014-10-30
        • 2010-10-20
        • 1970-01-01
        • 2018-03-31
        • 1970-01-01
        • 2020-07-12
        • 1970-01-01
        • 2013-01-22
        • 2010-09-26
        相关资源
        最近更新 更多