3

私が使用しているソフトウェア ライブラリは、大量のデバッグ出力を に書き込みますがstd::cerr、静かにするように指示すると、その出力をヌル ストリームにリダイレクトします。main.cppこれは、コードがこれを達成しようとする方法を示す簡略化されたものです。

#include <iostream>
#include <fstream>
#include <cassert>

// The stream that debug output is sent to. By default
// this points to std::cerr.
std::ostream* debugStream(&std::cerr);

// Throughout the library's codebase this function is called
// to get the stream that debug output should be sent to.
std::ostream& DebugStream()
{
    return *debugStream;
}

// Null stream. This file stream will never be opened and acts
// as a null stream for DebugStream().
std::ofstream nullStream;

// Redirects debug output to the null stream
void BeQuiet()
{
    debugStream = &nullStream;
}

int main(int argc, char** argv)
{
  DebugStream() << "foo" << std::endl;
  BeQuiet();
  DebugStream() << "bar" << std::endl;
  assert(debugStream->good());

  return 0;
}

このプログラムを実行すると、文字列 "bar" がヌル ストリームに正しく送信されていることがわかります。ただし、アサーションが失敗することに気付きました。これは私が心配する必要があるものですか?それとも、これはライブラリ開発者が選択したアプローチのわずかに醜い詳細ですか?

気が向いたら、より良い代替案の提案を歓迎します。いくつかの制約:

  • /dev/nullライブラリはクロスプラットフォームであるため、Windows では機能しないため、opening を使用することは有効な解決策ではないと思います
  • ライブラリは標準の C++ を使用するため、代替ソリューションではコンパイラ固有のものを使用しないでください。
4

2 に答える 2

3

この回答では、ストリームを他のストリームにリダイレクトするための一般的なヘルパーを見つけます。

class stream_redirector {
public:
    stream_redirector(std::ios& stream, std::streambuf* newBuf) :
        savedBuf_(stream.rdbuf()), stream_(stream)
    {
        stream_.rdbuf(newBuf);
    }

    ~stream_redirector() {
        stream_.rdbuf(savedBuf_);
    }

private:
    std::streambuf* savedBuf_;
    std::ios& stream_;
};

そして今、必要なのは、何も破棄するこの回答からのノーオペレーション ストリームだけです。

template <class cT, class traits = std::char_traits<cT> >
class basic_nullbuf: public std::basic_streambuf<cT, traits> {
    typename traits::int_type overflow(typename traits::int_type c)
    {
        return traits::not_eof(c); // indicate success
    }
};

template <class cT, class traits = std::char_traits<cT> >
class basic_onullstream: public std::basic_ostream<cT, traits> {
public:
    basic_onullstream():
    std::basic_ios<cT, traits>(&m_sbuf),
    std::basic_ostream<cT, traits>(&m_sbuf)
    {
        // note: the original code is missing the required this->
        this->init(&m_sbuf);
    }

private:
    basic_nullbuf<cT, traits> m_sbuf;
};

typedef basic_onullstream<char> onullstream;
typedef basic_onullstream<wchar_t> wonullstream;

そして、あなたは行ってもいいです:

int main(int argc, char** argv)
{
    std::cerr << "foo" << std::endl;
    {
        onullstream nos;
        stream_redirector sr( std::cerr, nos.rdbuf() );
        std::cerr << "bar" << std::endl;
    }
    std::cerr << "baz" << std::endl;
}

最後に、実際に試してみたい場合に備えて、実際の例を示します。この方法には、あなた (およびあなたの同僚) がstd::cerrコードで引き続き使用できる追加の利点があり、自由にオン/オフを切り替えることができます :)

于 2013-10-05T17:31:26.937 に答える