调试功能"消失"在某些情况下

时间:2014-12-04 16:06:48

标签: c++ debugging c++11

假设我有一个如下定义的调试函数:

namespace debug {
    void report(std::string message);
}

我可以提取一些编译器技巧,在编译时,用nop安全地替换每个调用。我不想调用空函数,我想根本不调用函数。

如果有可能......我可以创建名称空间"也会消失吗?

调试可执行文件将使用定义的符号DEBUGEXECUTABLE进行编译(我可以想象一些带有宏的技巧)。

3 个答案:

答案 0 :(得分:5)

您可以这样做:

namespace debug
{
    void report(std::string message); // ToDo - define this somewhere
}

namespace release
{
    template <class Y>    
    void report(Y&&){} // Intentionally do nothing
}

#if defined(DEBUGEXECUTABLE)
    namespace foo = debug;  // set foo to the debug namespace
#else
    namespace foo = release; // set foo to the release namespace
#endif

然后在代码中使用foo::report。我喜欢这个,因为它最大限度地减少了预处理器宏的使用,并使调试和发布配置中的任何编译器错误大致相似。

在发布模式下传递 r值引用将允许编译器优化任何匿名临时值。对于调试函数系列,您应该通过常量引用传递字符串,以避免采用值复制的任何可能性:void report(const std::string& message);

答案 1 :(得分:3)

这是我能做到的最佳选择。

我们将DEBUG定义为有report做某事,然后不做任何事情:(或者我们可以使用您在构建过程中使用的任何符号来区分debug和opt来自生产代码)

#define DEBUG

我们创建两个名称空间。一个称为debug,另一个称为release。在每个中我们创建一个匿名命名空间,这使编译器可以轻松检测和丢弃未使用的函数:

namespace debug {
  namespace {
    void report(std::string const& s) {
      std::cerr << s << "\n"; // sample implementation
    }
  }
}
namespace release {
  namespace {
    template<class T>
    void report(T&&) {} // Or `class...Ts` and `Ts&&...` to handle more than 1 argument optionally.
  }
}

这里我们创建一个在发布和调试方面不同的命名空间别名:

#ifdef DEBUG
namespace report=debug;
#else
namespace report=release;
#endif

我们的主要内容:

int main() {
  report::report("hello");
}

我们可以在gcc 4.9下看到此结果,其中DEBUG definednot位于godbot。正如您所希望看到的那样,当#define DEBUG未定义时,编译器只生成空main

如果已定义,则会编译为您期望的内容。

答案 2 :(得分:0)

namespace debug {
#ifdef DEBUGEXECUTABLE
    void report(std::string message);
#else
    inline void report(std::string message)
    {
        //nop - compiler should optimize it
    }
#endif
}