2

计时器.h:

class Timer
{
public:
void start();
void printTimeAndRestart(const char* msg);
};
namespace Timing {    static 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

timer 将在许多不同的文件中使用,例如:

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(); 但这需要重新编译整个代码来打开/关闭它们......

4

5 回答 5

3

这取决于你如何使用它。如果它是同一个项目/解决方案并且编译器能够进行完整的程序优化,那么它可能是无关紧要的。

如果您正在分发带有二进制文件的代码并且实现不可见,并且编译器无法判断它是空的,那么由于调用会产生一些(较小的)开销。

于 2013-03-21T15:59:27.173 回答
0

如果函数被定义为“内联”(即,作为声明它们所属类的头文件的一部分),那么编译器可以避免为空函数生成代码。如果函数在 .cpp 文件中,编译器必须生成代码来调用函数,因为编译器无法知道函数的作用[除非编译器支持“整个程序优化”]。

我的解决方案是将函数移动到头文件中,而不是使用宏。这是一个更简洁的解决方案,除非编译器绝对是垃圾,否则它应该将其分类为“没有生成代码”。

于 2013-03-21T16:01:54.487 回答
0

在调试版本中,这将被调用,并将具有任何函数调用的整体效果。在一般优化代码中,编译器会省略调用。

根据下面的评论。

在调用站点,编译器将无法确定被调用函数无效。如果您的宏还内联定义了空条件,那么调用站点将能够看到该函数本质上是一个 noop。

于 2013-03-21T15:57:18.027 回答
0

如果您想更确定编译器将优化调用,请执行以下操作:

计时器.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

计时器.cpp:

#ifdef DO_TIMING
//implementation
void Timer::start() { ... };
void Timer::printTimeAndRestart(const char* msg) { ... };
#endif
于 2013-03-21T16:00:32.030 回答
0

无论如何,高质量的编译器可能会删除它,但确保将空函数内联在 .h 文件中会更安全:

定时器.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; }

定时器.cpp

#ifdef DO_TIMING

// ...

#endif

不幸的是,这确实意味着您将依赖项绑定到标头中,这将导致在打开或关闭时重新编译。

于 2013-03-21T16:01:01.170 回答