2014-12-04 81 views
2

假设我有一个是这样定义的调试功能:调试功能“消失”在某些情况下

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

我能拉一些编译器技巧,将编译的时候,安全与nop代替每个呼叫。我不想调用一个空函数,我不想调用函数。

如果有可能......我可以让命名空间“消失”吗?

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

+0

请注意,调用一个空函数会导致编译器转到“嘿,为什么我要调用一个空函数?”,并优化调用。因此,为什么大多数答案显示使用宏来调用非调试版本中的空函数。 – KidneyChris 2014-12-04 16:15:45

回答

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);

+0

这仍然是一个'std :: string'副本。试试'template void report(T &&){}'?从技术上讲,这导致它的论点被ODR使用,但不知道如何避免。作为一个例子,'report(“hello”)'在调试和释放中都会导致分配。 – Yakk 2014-12-04 16:18:38

+0

不足 - 'report(“hello”)'不应该在release中分配。 – Yakk 2014-12-04 16:20:52

+0

我喜欢命名空间的想法,我想我会从@Mateusz Drost(+引用)的内联技巧。我会在明天objdump结果并告诉你gcc-4.8是否优化它。 – WorldSEnder 2014-12-04 16:33:35

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

'report(“hello”)'在你的发布版本中导致分配。编译器不太可能优化它。 – Yakk 2014-12-04 16:23:32

+0

1)大多数编译器会优化它,除非你设置O0 2)如果你设置00你不关心nonoptimise分配;) 3)但如果你关心,那么只需使用const std :: string&和const char * 4)我只是使用问题 – 2014-12-04 16:29:27

+0

- 1的声明:[不,你是不正确的](http://goo.gl/uSzFsn) - 删除分配不是一个微不足道的行为,并没有遵循as-if规则。 – Yakk 2014-12-04 16:34:59

3

这是最佳的,因为我可以把它。

我们定义DEBUGreport,做什么,离开它,它什么都不做(或者我们可以使用您使用在构建过程中的任何符号来区分调试和生产代码选择)

#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的结果与DEBUGdefined和。正如你所希望的那样,当#define DEBUG没有被定义时,编译器只产生一个空的main

如果定义了它,它将编译为您所期望的。

+1

因为我学习了新的东西,所以我想加倍努力。 ('namespace ... = ...;') – LyingOnTheSky 2014-12-04 16:46:18

相关问题