将宏转换为内联函数

时间:2010-06-16 13:13:30

标签: c++

我正在使用一些Qt代码添加一个看起来像这样的VERIFY宏:

#define VERIFY(cond) \
{ \
    bool ok = cond; \
    Q_ASSERT(ok); \
}

然后代码可以使用它,同时确定实际评估条件,例如:

Q_ASSERT(callSomeFunction()); // callSomeFunction not evaluated in release builds!
VERIFY(callSomeFunction());   // callSomeFunction is always evaluated

不喜欢宏,我想把它变成一个内联函数:

inline VERIFY(bool condition)
{
  Q_ASSERT(condition);
}

但是,在发布版本中,我担心编译器会优化对此函数的所有调用(因为Q_ASSERT实际上不会做任何事情。)我不必要地担心或者这可能取决于优化标志/编译器/等。?我想我可以把它改成:

inline VERIFY(bool condition)
{
  condition;
  Q_ASSERT(condition);
}

但是,再次,编译器可能足够聪明以忽略该调用。

这种内联替代方案对于调试和发布版本都是安全的吗?

4 个答案:

答案 0 :(得分:4)

即使编译器优化了你的内联VERIFY函数,那也不意味着它不会调用生成bool参数的函数。

Q_ASSERT没有调用在发布版本中传递给它的函数的原因是它是一个根本不能替换函数调用的宏,所以没有什么可以优化的。

答案 1 :(得分:2)

如果是内联函数,则无法保证不评估函数参数。

由于他们的评估可能有或没有副作用,您最好在维护代码时遇到困难 - 如果出现副作用,肯定会进行评估,在其他情况下,将需要或不在编译器的自由裁量权。这将为您提供一个以松散控制的方式运行的程序。

因此,即使您不喜欢宏,也应该做出明智的决定。要么使用宏,然后预处理器消除整个构造,并且不评估参数,要么使用内联函数,然后编译器为您决定。

答案 2 :(得分:0)

优化器不会删除有副作用的代码,否则优化程序会改变它的工作方式!在这种情况下,如果函数参数有副作用(例如,将某些内容打印到控制台),则它将始终被评估,即使传递给它的函数已完全消除。

想象一下这段代码:

int x = Return5();
int y = PrintToConsoleAndReturn5();

// x and y never used again

优化器可以省略对Return5()的调用(假设它只包含return 5;),因为它没有副作用,因此整行不会发出任何操作。但是,优化器不能省略对PrintToConsoleAndReturn5()的调用(但它可以内联它),因为它有副作用。它可以省略返回整数5并将其存储到y,因为该代码没有副作用。简而言之,理论是程序的行为应该是相同的,无论是优化的还是未经优化的,所以你应该对原始问题没问题。

答案 3 :(得分:0)

在优化期间,编译器仍必须遵守手头代码的可观察效果。这意味着如果调用可观察的话,它必须保留callSomeFunction()。 (有一些特殊的例外适用于复制周围的对象,可以注意到副本的消除 - 这里无关紧要。)

但是,在发布模式下,Q_ASSERT(callSomeFunction());的优化无关紧要。完成预处理器时,没有什么可以优化的,Q_ASSERT宏已经扩展了!