2009-04-17 9 views
30

Info、Errorなどのメンバーを持ち、コンソール、ファイル、またはどこにも出力できないロギングクラスを作っています。no-op std :: ostreamの実装

効率を上げるために、捨てるメッセージを整形する際のオーバーヘッドを避けたいと考えています(冗長モードで実行していないときの情報メッセージなど)。どこにも出力されないカスタムstd :: streambufを実装すると、std :: ostreamレイヤーはまだすべてのフォーマットを行うと想像します。誰もが本当に "ヌル" stdを持っている方法を提案することができます::ストリームは<<とそれに渡されたパラメータ上のすべての作業を行うことを避ける?

ありがとうございました。

+0

私は心配しません。 neilで示されるようなヌルストリームを使用してください。明らかにあなたがヌルのターゲットを持っていない場合、フォーマット*が*行われているので、クラスはそれ以上のパフォーマンスを必要としないので、明らかに重要ではありません。ちょうど私の2セント –

+0

ええと、それは "デバッグ出力"のthingyとして意図されているようですね?私が見た1つの方法は次のようなものです:out()<< a << b ...; out()はstruct f {}を返します。テンプレートなしの場合 f const&operator <<(f const&f_、T const){return f_; }、ログレベルに応じて異なる構造体を返すようにしてください。異なる機能や何かを作成することができます。 –

答えて

4

呼び出しをoperator<<()がフォーマットしないようにするには、コンパイル時にstreamtypeを知っておく必要があります。これは、マクロまたはテンプレートを使用して行うことができます。

私のテンプレートソリューションは次のとおりです。

class NullStream { 
public: 
    void setFile() { /* no-op */ } 
    template<typename TPrintable> 
    NullStream& operator<<(TPrintable const&) 
    { /* no-op */ } 
} 

template<class TErrorStream> // add TInfoStream etc 
class Logger { 
public: 
    TErrorStream& errorStream() { 
     return m_errorStream; 
    } 

private: 
    TErrorStream m_errorStream; 
}; 

//usage 
int main() { 
    Logger<std::ofstream> normal_logger; // does real output 
    normal_logger.errorStream().open("out.txt"); 
    normal_logger.errorStream() << "My age is " << 19; 

    Logger<NullStream> null_logger; // does zero output with zero overhead 
    null_logger.errorStream().open("out.txt"); // no-op 
    null_logger.errorStream() << "My age is " << 19; // no-op 
} 

これはコンパイル時に行う必要があるため、当然ながら柔軟性がありません。

例えば、実行時に設定ファイルからロギングレベルを決定することはできません。

+0

+1:シンプルで清潔で、仕事はうまくいっています。例えば、"NullStream s;" expensive_function(); "特にそれが別のモジュールにある場合には、おそらくexpensive_function()を評価するでしょう。 –

+3

また、Neilのonullstreamとは異なり、NullStreamはostream&or ostream *引数を期待する関数に渡すことはできません。 –

+0

expensive_function()はどこにいても評価されます。マクロと条件付きコンパイルを禁止する方法はありません:) ... Neilのストリームについては、「ゼロフォーマットオーバーヘッド」の要件を満たしているとは思われません:) –

0

おそらく、テキストフォーマットとメッセージフィルタリング以上のものが必要になるでしょう。マルチスレッドはどうですか?

私はフィルタリングとマルチスレッド同期を別のクラスの責任として実装します。

しかし、ロギングはそれほど単純な問題ではなく、新しいものを開発する代わりに、既存のロギングソリューションを使用しようとします。

15

速いgoogleが役に立つかもしれないこの例が思い付きました。私は、何百万ものユーザーによって使用される既存のログ・ソリューションを使用していないのはなぜそれが

#include <streambuf> 
#include <ostream> 

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) 
     { 
      init(&m_sbuf); 
     } 

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

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

int main() { 
    onullstream os; 
    os << 666; 
} 
+0

+1。はい、私は、ostream&またはostream *パラメータを期待する関数に何もしないストリームを渡したい場合は、std :: basic_ostream <>から派生する必要があると思います - Iraimbilanjaのトリックはそこでは機能しません。 –

+0

それは 'ostream *'として受け入れることができ、 'ostream&'ではなく、是正することができますか? – athos

0

:-)コンパイルし、実行されることを除いて、何の保証を提供していますか? のlog4j、log4netの、log4cxx ...、名前にわずか数..

13

すべて、コードを共有するためのおかげで、私はテストを行う、そしてニールの方法はまだ、たとえば、文字列の整形を行います。

このプログラムを実行する
#include <streambuf> 
#include <ostream> 
#include <iostream> 
using namespace std; 


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) 
     { 
      init(&m_sbuf); 
     } 

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

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

class MyClass 
{ 
    int a; 
    friend ostream& operator<< (ostream&, MyClass const&); 
}; 

ostream& operator<<(ostream& out,MyClass const& b) 
{ 
    std::cout<<"call format function!!"; 
    out << b.a; 
    return out; 
} 

int main() { 
    onullstream os; 
    MyClass obj; 
    os<<obj; 
} 

、あなたは "ostreamに&オペレータ< <(ostreamに&うち、MyClassののconstの& b)は" と呼ぶことにすること。わかりますしたがって、objの書式を実行することは依然として呼び出されます。したがって、メッセージの書式設定のオーバーヘッドを回避することはできません。

+0

AFAIKオプティマイザは副作用のないコードを削除できます。 'std :: cout <<"コールフォーマット関数の呼び出しは副作用があるので、オプティマイザはこれを削除しません。ただし、コールがなければ、これは削除される可能性があります –

関連する問題