1

初めての投稿ですので、皆様のご来店を心よりお待ちしております。私が発生した問題は、コンパイル時のコードの最適化であり、より具体的には、デバッグ印刷の削除です。

syslog loggerネイティブがあり、次のコードでラップしていると想像してみてください(マクロを使用せずに、非常に重要な注意事項です!)。

enum severity { info_log, debug_log, warning_log, error_log };
template <severity S>
struct flusher {
  logger* log_;
  flusher(logger* log) : log_(log) {}
  flusher(flusher& rhs) : log_(rhs.log_) {}
  ~flusher() { syslog(S, log_->stream.str()); log_->stream.str(""); }
  operator std::ostream& () { return log_->stream; }
};
#ifdef NDEBUG
template <> struct flusher<debug_log> {
  flusher(logger*) {}
  flusher(flusher&) {}
  ~flusher() {}
  template <typename T> flusher& operator<<(T const&) { return *this; }
};
#endif
struct logger {
  std::ostringstream stream;
  template <severity T>
  flusher<T> operator<<(flusher<T> (*m)(logger&)) { return m(*this); }
};
inline flusher<info_log> info(logger& log) { return flusher<info_log>(&log); }
inline flusher<debug_log> debug(logger& log) { return flusher<debug_log>(&log); }
inline flusher<warning_log> warning(logger& log) { return flusher<warning_log>(&log); }
inline flusher<error_log> error(logger& log) { return flusher<error_log>(&log); }

フラッシャーの空の実装は、コンパイラーがそのような役に立たないコードを削除することを奨励すると思いましたが、両方O2O3使用すると、削除されません。

言及された行動を誘発する可能性はありますか?

前もって感謝します

4

4 に答える 4

2

少なくとも2つの違いはありますが、私はあなたが試みていることを正常に実行しました... 1)テンプレートを使用していませんでした-コンパイラが最適化できない複雑さを作成している可能性があります、2)ログの使用にはマクロ(以下を参照)。

さらに、すでにこれを行っている可能性があります。すべての「空の」定義がロガーのヘッダーファイルにあることを確認してください(最適化はコンパイル時に行われ、リンク時に延期されません)。

// use it like this
my_log << "info: " << 5 << endl;

リリース定義は次のようになります。

#define my_log if(true);else logger

デバッグ定義は次のようになります。

#define my_log if(false);else logger

コンパイラは、リリースですべてのif(true)に対してロガーを最適化し、デバッグでロガーを使用することに注意してください。また、両方の場合の完全なif / else構文は、スコープ外で使用する面白い状況を回避することに注意してください。

if (something)
    my_log << "this" << endl;
else
    somethingelse();

それがないとmy_logになりますsomethingelseelse

于 2013-02-06T17:56:40.753 に答える
0

したがって、コメントのコードに従ってください:

inline int f() 
{ 
  std::cout << 1; 
  return 1; 
}

次のようにする必要があります:

inline int f() 
{ 
#ifndef NDEBUG
   std::cout << 1; 
#endif
   return 1; 
}

またはこのようなもの:

#ifndef NDEBUG
static const int debug_enable = 1;
#else
static const int debug_enable = 0;
#endif    


inline int f() 
{ 
   if (debug_enable)
   {
       std::cout << 1; 
   }
   return 1; 
}

どういうわけか、このコードは必要ないことをコンパイラに伝える必要があります。

于 2013-02-06T17:56:20.887 に答える
0

現在のコードは、f()の呼び出しとそれが持つ可能性のある副作用を妨げておらず、実際の印刷を妨げているだけです。これが、マクロがこの問題に対する従来のアプローチである理由です。マクロは、実際に印刷する前に値を印刷する必要があるかどうかを確認できる未評価のコンテキストを提供します。

マクロなしでこれを実現するには、std :: function、関数ポインターなどの追加の間接参照が必要です。例として、std :: functionを含むラッパークラスを提供し、ストリーム演算子を特殊化してstdを呼び出すことができます。 :: NDEBUGの場合ではなく、デフォルトの場合の関数

非常に大まかな例:

//Wrapper object for holding std::functions without evaluating
template <typename Func>
struct debug_function_t {
    debug_function_t(Func & f) : f(f) {}
    decltype(f()) operator()() { return f(); }
    std::function<Func> f;
};

//Helper function for type deduction
template <typename Func>
debug_function_t<Func> debug_function(Func & f) { 
    return debug_function_t<Func>(f);
}

struct debug_logger {

    template <typename T>
    debug_logger & operator<<(T & rhs) {}

    template <typename Func> //Doesn't call f(), so it's never evaluated 
    debug_logger & operator<<(debug_function_t<Func> f) { } 

};

次に、クライアントコードで

int f(){ std::cout << "f()\n"; }
debug_logger log;
log << debug_function(f);
于 2013-02-06T18:05:45.867 に答える
0

私がいくつかのゲームで使用した手法では、デバッグ印刷が一般的な式ではなく関数である必要があります。例えば:

debug_print("this is an error string: %s", function_that_generates_error_string());

リリースモードでは、の定義debug_printは次のとおりです。

#define debug_print sizeof

debug_printこれにより、実行可能ファイルから渡された式が削除されます。それでも有効な式を渡す必要がありますが、実行時に評価されません。

于 2013-02-06T20:04:12.300 に答える