标准无操作输出流

Maë*_*son 40 c++ iostream

有没有办法创建一个基本上什么都不做的ostream实例?

例如 :

std::ostream dummyStream(...);
dummyStream << "Nothing will be printed";
Run Code Online (Sandbox Code Playgroud)

我可以创建一个ostringstream,但数据将被缓冲(我真的不想用它们做任何事情,所以它增加了无用的开销).

任何的想法 ?

[编辑]找到适合我需要的相关问题.但是,我认为如何使用标准c ++ 创建有效(无badbit)输出流的答案可能会有用.

joh*_*ohn 63

你需要一个自定义的streambuf.

class NullBuffer : public std::streambuf
{
public:
  int overflow(int c) { return c; }
};
Run Code Online (Sandbox Code Playgroud)

然后,您可以在任何ostream类中使用此缓冲区

NullBuffer null_buffer;
std::ostream null_stream(&null_buffer);
null_stream << "Nothing will be printed";
Run Code Online (Sandbox Code Playgroud)

streambuf::overflow是缓冲区必须将数据输出到流的实际目标时调用的函数.NullBuffer当调用溢出时,上面的类什么也不做,所以使用它的任何流都不会产生任何输出.

  • 可以创建一个便利类`class NullStream:public std :: ostream {public:NullStream():std :: ostream(&m_sb){} private:NullBuffer m_sb; };`,它简化了对NullStream null_stream的使用; null_stream << ...` (17认同)
  • 只是一个提示:该函数可能会产生故障,从而将流转换为故障状态(不过,大多数人都不会在意)。为了避免这种情况,您需要返回`not_eof()的结果。另外,缓冲字符比在假定不太可能的路径上调用`virtual`函数更有效,也就是说,我还建议添加设置一个被忽略的缓冲。覆盖将变成`int溢出(int c){返回this-&gt; setp(std :: begin(d_buffer),std :: end(this-&gt; d_buffer); std :: char_traits &lt;char&gt; :: not_eof(c)类似地,覆盖xsputn()而不执行任何操作可能是合理的。 (2认同)
  • @DietmarKühl:您介意将其编辑为答案,还是自己编写? (2认同)

jxh*_*jxh 32

如果这是禁用日志记录输出,您dummyStream仍然会导致参数被评估.如果要在禁用日志记录时将影响降至最低,则可以依赖条件,例如:

#define debugStream \
    if (debug_disabled) {} \
    else std::cerr
Run Code Online (Sandbox Code Playgroud)

所以如果你有像这样的代码:

debugStream << "debugging output: " << foo() << std::endl;
Run Code Online (Sandbox Code Playgroud)

如果debug_disabled为真,则不会评估任何参数.


Die*_*ühl 5

已经有一些答案,但我认为值得添加,但是,另一个答案是基于我所做的评论。如何创建不产生任何数据的流,本质上存在三种明显的变化:

  1. 最简单的版本是将流设置为非操作状态。但这与要求工作流的规范不符:

    std::ostream null(nullptr);
    
    Run Code Online (Sandbox Code Playgroud)
  2. 正如其他答案所提到的,从中派生流std::sttreambuf并覆盖overflow(int)以返回成功,但其他答案什么也不做:

    struct NullBuffer
        : std::streambuf {
        int overflow(int c) override { return c; }
    };
    
    Run Code Online (Sandbox Code Playgroud)

    这是输入的最短版本,但正如已经评论的那样,我不认为这是最快的方法。

  3. 我希望流缓冲区实际上使用一个小缓冲区并且重写速度xsputn()更快:

    struct NullBuf
        : std::streambuf {
        char buffer[100];
        int overflow(int c) override {
            setp(buffer, buffer + sizeof buffer);
            return c;
        }
        std::streamsize xsputn(const char*, std::streamsize n) override {
            return n;
        }
    };
    
    Run Code Online (Sandbox Code Playgroud)

    小缓冲区可能更好的原因是流不需要virtual每次都检查缓冲区是否为空并调用函数。相反,它会检查是否有缓冲区,并且偶尔会调用该virtual函数。

当对三个版本运行基准测试时,我得到以下结果:

Running ./bin/clang--2a/nullstream.tsk
Run on (8 X 24 MHz CPU s)
CPU Caches:
  L1 Data 64 KiB
  L1 Instruction 128 KiB
  L2 Unified 4096 KiB (x8)
Load Average: 1.22, 1.52, 2.04
-----------------------------------------------------------
Benchmark                 Time             CPU   Iterations
-----------------------------------------------------------
BM_NullStreambuf        101 ns          101 ns      6883531
BM_NullBuffer          1430 ns         1430 ns       488561
BM_NullBuf              748 ns          748 ns       931309
Run Code Online (Sandbox Code Playgroud)

也就是说,想要一个无故障的流而不是简单地完全禁用该流需要付出巨大的代价。使用缓冲区和覆盖xsput()可以显着提高性能。当然,这些是使用特定输出的微观基准,尽管我并没有试图太聪明:我包含了一个字符串(应该使用xsputn()),并且包含了一个具有更多位数的整数,以使流使用std::ostreambuf_iterator<char>和旁路xsputn()。完整的基准测试如下。

该代码是使用编译的

clang++ -std=c++2a  -W -Wall -I/usr/local/include -O3 -c -o nullstream.o nullstream.cpp
clang++ -L/usr/local/lib -o nullstream.tsk nullstream.o -lbenchmark -lbenchmark_main
Run Code Online (Sandbox Code Playgroud)

M2 MacBook 上的版本clang是最新的。我还没有在其他计算机上运行它或使用不同的 IOStream 实现,但我希望得到类似的结果。

#include <benchmark/benchmark.h>
#include <ostream>
#include <limits>

void run_benchmark(benchmark::State& state, std::ostream& out) {
  for (auto _ : state) {
      for (int i{0}; i != 10; ++i) {
          out << (std::numeric_limits<int>::max() - i)
              << "0123456789012345678901234567890123456789"
              << "\n";
      }
  }
}

struct NullBuffer
    : std::streambuf {
    int overflow(int c) override { return c; }
};

struct NullBuf
    : std::streambuf {
    char buffer[100];
    int overflow(int c) override {
    setp(buffer, buffer + sizeof buffer);
        return c;
    }
    std::streamsize xsputn(const char*, std::streamsize n) override {
        return n;
    }
};

static void BM_NullStreambuf(benchmark::State& state) {
  std::ostream null(nullptr);
  run_benchmark(state, null);
}

static void BM_NullBuffer(benchmark::State& state) {
  NullBuffer   buf;
  std::ostream null(&buf);
  run_benchmark(state, null);
}

static void BM_NullBuf(benchmark::State& state) {
  NullBuf      buf;
  std::ostream null(&buf);
  run_benchmark(state, null);
}

BENCHMARK(BM_NullStreambuf);
BENCHMARK(BM_NullBuffer);
BENCHMARK(BM_NullBuf);

BENCHMARK_MAIN();
Run Code Online (Sandbox Code Playgroud)