3

私は本当に単純なスレッドセーフなロガーを書こうとしています。理想的には、 のように機能するようにしたいと考えていましたstd::cout。この場合、オペレーターをオーバーロードするだけ<<で、魔法のようにすべてがログに表示されます。私はWindowsマシンを使用しているので、試したアプローチは次のとおりです。

// Threadsafe logger
class Logger
{
public:
  Logger()
  {
    InitializeCriticalSection(&s);
  }

  ~Logger()
  {
    DeleteCriticalSection(&s);
  }

  void Log(std::ostream const& os)
  {
    EnterCriticalSection(&s);
    //std::cout << static_cast<std::stringstream const&>(os).str();
    std::cout << os.rdbuf();
    LeaveCriticalSection(&s);
  }

private:
  CRITICAL_SECTION s;
};

関数に対して 2 つのアプローチを試みたことに注意してくださいLog()。私が an を受け入れる理由は、オペレーターが呼び出された後に a が生成するように見えるからostreamです。このコードを実行すると、関数の両方のバリアントが同じように失敗します。stringstream<<Log()

#include <iostream>
#include <sstream>
#include <Windows.h>

int main(int argc, char* argv[])
{
  Logger logger;
  //logger.Log(std::stringstream("Test"));
  logger.Log(std::stringstream("Another ") << "test");
  std::cin.get();
}

最初の行 ("Test") の出力は正しく機能し、Log 関数の両方のバリアントを使用して正しく表示されます。2 行目は、マングルされた出力を出力します。

testher

これは明らかにtest上書きされていAnotherます。これらのストリームの仕組みについて何が欠けていますか? flush問題が解決することを期待して電話をかけてみましたが、何もしませんでした。

スレッドセーフロガーがストリームで正しく動作するようにするにはどうすればよいですか?

4

4 に答える 4

3

可変個引数テンプレートの使用:

void Log_impl(std::ostream &os) {} // recursion base case

template<typename T,typename... Us>
void Log_impl(std::ostream &os,T &&t,Us &&... us) {
    os << std::forward<T>(t);
    Log_impl(os,std::forward<Us>(us)...);
}

template<typename... Ts> void Log(Ts &&... ts) {
    std::stringstream ss;
    Log_impl(ss,std::forward<Ts>(ts)...);
    fprintf(stdout,"%s\n",ss.str().c_str()); // thread safe output
}

利用方法:

Log("Another"," test ",100);

私は実際にこのコードをテストしていません...

于 2012-04-11T17:35:10.817 に答える
0

<< は、作成した一時的な stringstream("Another ") に "test" の末尾にある null バイトを送信しません。これが、"tester" が表示される理由です。

于 2012-04-11T16:35:58.083 に答える