Timer.h:
class Timer
{
public:
void start();
void printTimeAndRestart(const char* msg);
};
namespace Timing { static Timer timer; }
Timer.cpp:
#ifdef DO_TIMING
//implementation
void Timer::start() { ... };
void Timer::printTimeAndRestart(const char* msg) { ... };
#else
//empty - do not do timing
void Timer::start() {};
void Timer::printTimeAndRestart(const char* /*msg*/) {};
#endif
计时器将用于许多不同的文件,如:
Timing::timer.start();
...
Timing::timer.printTimeAndRestart("Operation X took :");
如果应用程序对性能非常敏感且经常调用定时器,那么在未定义DO_TIMING时调用空方法会影响性能吗?什么是实现隔离计时器的更好选择(无需重新编译整个项目以打开/关闭),这在关闭时根本不会影响性能。
到目前为止,我只能想到定义像
这样的宏#ifdef DO_TIMING
#define START_TIMING()
Timing::timer.start();
#endif
#else
#define START_TIMING()
#endif
并使用它们代替Timing :: timer.start();但这需要重新编译整个代码才能打开/关闭它们......
答案 0 :(得分:3)
这取决于你如何使用它。如果它是相同的项目/解决方案并且编译器能够进行完整的程序优化,那么它可能是无关紧要的。
如果您使用二进制文件分发代码并且实现不可见,并且编译器无法告诉它为空,则由于调用会产生一些(次要的)开销。
答案 1 :(得分:0)
在调试版本中,这将被调用,并且将具有任何函数调用的整体效果。在优化代码中,编译器通常会省略调用。
根据以下评论。
在调用站点,编译器将无法确定被调用函数无效。如果您的宏也定义了内联的空条件,那么调用站点将能够看到该函数基本上是一个noop。
答案 2 :(得分:0)
如果您想更加确定编译器将优化呼叫,请执行以下操作:
Timer.h:
class Timer
{
public:
void start();
void printTimeAndRestart(const char* msg);
};
namespace Timing { static Timer timer; }
#ifndef DO_TIMING
inline void Timer::start() {}
inline void printTimeAndRestart(const char*) {}
#endif
Timer.cpp:
#ifdef DO_TIMING
//implementation
void Timer::start() { ... };
void Timer::printTimeAndRestart(const char* msg) { ... };
#endif
答案 3 :(得分:0)
高质量的编译器可能会删除它,但是确保在.h文件中内联空函数更安全:
Timer.h
class Timer
{
public:
void start();
void printTimeAndRestart(const char* msg);
};
#ifndef DO_TIMING
inline void Timer::start() {}
inline void printTimeAndRestart(const char* msg) {}
#endif
namespace Timing { static Timer timer; }
Timer.cpp
#ifdef DO_TIMING
// ...
#endif
不幸的是,这确实意味着你将一个依赖项绑定到标题中,这将导致在打开或关闭时重新编译。
答案 4 :(得分:0)
如果函数被定义为“inline”(即,作为声明它们所属的类的头文件的一部分),则编译器可以避免为空函数生成代码。如果函数在.cpp文件中,编译器必须生成调用函数的代码,因为编译器无法知道函数的作用[除非编译器支持“整个程序优化”]。
我的解决方案是将函数移动到头文件中,而不是使用宏。这是一个更简洁的解决方案,除非编译器绝对是垃圾,否则它应该将其排除为“无代码生成”。