There are some answers already but I think it is worth add, yet, another answer building on a comment I made.  There are essentially three obvious variations how to create a stream which doesn't produce any data:
- The simplest version is to just set the stream into a non-operational state. That doesn't match the specification asking for a working stream, though: - std::ostream null(nullptr);
 
- As mentioned by other answers, deriving a stream from - std::sttreambufand just overriding- overflow(int)to return success but other doing nothing:
 - struct NullBuffer
    : std::streambuf {
    int overflow(int c) override { return c; }
};
 - This is the shortest version to type but as commented already, I don't think this is the fastest approach. 
- I'd expect a stream buffer actually using a small buffer and also overriding - xsputn()to be faster:
 - 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;
    }
};
 - The reason a small buffer is likely better is that the stream doesn't need to check if the buffer is empty and call - virtualfunction each time. Instead, it would check find that there is buffer and only once in a while call the- virtualfunction.
 
When running a benchmark for the three versions I get these results:
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
That is, there is a substantial cost for wanting a non-failing stream rather than simply disabling the stream entirely. Using a buffer and overriding xsput() is a significant performance boost. Of course, these are micro benchmarks using a particular output although I didn't try to be too smart: I included a string (which should use xsputn()) and I included an integer with a bigger number of digits to cause the stream to use the std::ostreambuf_iterator<char> and bypass xsputn(). The full benchmark is included below.
The code was compiled using
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
The version of clang is up to date on an M2 MacBook. I haven't run it on other computers or using a different IOStream implementation but I would expect similar results.
#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();