什么是双重评估,为什么要避免?
我正在用C ++读取这个macros
#define max(a,b) (a > b ? a : b) 可以导致“双重评估”。 有人能给我举一个例子,说明什么时候发生双重评估,为什么不好?
PS:奇怪的是我找不到任何详细的解释,除了在Clojure (我不明白)的例子。
想象一下,你写这个:
 #define Max(a,b) (a < b ? b : a) int x(){ turnLeft(); return 0; } int y(){ turnRight(); return 1; } 
然后这样调用它:
 auto var = Max(x(), y()); 
 你知道turnRight()会执行两次吗? 那个macros, Max会扩展到: 
 auto var = (x() < y() ? y() : x()); 
 在评估了条件x() < y() ,程序接着在y() : x()之间取得所需的分支:在我们的例子中是true , 第二次调用y() 。 看到它住在Coliru 。 
 简单地说,将一个expression式作为parameter passing给类似函数的macros , Max将潜在地评估该expression式两次,因为在macros的定义中使用macrosexpression式时,expression式将被重复。 请记住, macros是由预处理器处理的 。 
所以,底线是,不要使用macros来定义一个函数(在这种情况下,实际上是一个expression式),因为您希望它是通用的 ,而使用函数模板
  PS:C ++有一个std::max模板函数。 
  a和b在macros定义中出现两次。 所以如果你使用带有副作用的参数,副作用会被执行两次。 
 max(++i, 4); 
 如果在呼叫之前i = 4 ,将返回6。 由于这不是预期的行为,所以您应该更喜欢内联函数来replace像max这样的macros。 
考虑下面的expression式:
  x = max(Foo(), Bar()); 
  Foo和Bar是这样的: 
 int Foo() { // do some complicated code that takes a long time return result; } int Bar() { global_var++; return global_var; } 
 然后在原来的maxexpression式扩展如下: 
  Foo() > Bar() ? Foo() : Bar(); 
 无论哪种情况,Foo或Bar都要执行两次。 从而花费比所需时间更长的时间或改变程序状态超过预期的次数。 在我简单的Bar示例中,它不会始终返回相同的值。 
  C和C ++中的macros语言在“预处理”阶段由专用parsing器处理; 令牌被翻译并且输出然后被馈送到parsing器本身的inputstream中。  #define和#include标记不被C或C ++parsing器自己识别。 
这很重要,因为这意味着当一个macros被说成是“扩展”的时候,这就意味着这个意思 。 特定
 #define MAX(A, B) (A > B ? A : B) int i = 1, j = 2; MAX(i, j); 
C ++parsing器看到的是什么
 (i > j ? i : j); 
但是,如果我们用更复杂的macros来使用macros,就会发生相同的扩展:
 MAX(i++, ++j); 
扩大到
 (i++ > ++j ? i++ : ++j); 
如果我们传递一个可以调用函数的东西:
 MAX(f(), g()); 
这将扩大到
 (f() > g() ? f() : g()); 
 如果编译器/优化器可以certificatef()没有副作用,那么它将把它当作 
 auto fret = f(); auto gret = g(); (fret > gret) ? fret : gret; 
如果不能,那么它将不得不调用f()和g()两次,例如:
 #include <iostream> int f() { std::cout << "f()\n"; return 1; } int g() { std::cout << "g()\n"; return 2; } #define MAX(A, B) (A > B ? A : B) int main() { MAX(f(), g()); } 
现场演示: http : //ideone.com/3JBAmF
 同样,如果我们调用一个extern函数,优化器可能无法避免两次调用该函数 。