在代码中唯一标识方法调用的方法,用于测试调用序列是否未更改

时间:2012-08-16 14:44:11

标签: c++

我们正在开发一个新的中断系统(在c ++中),以替换旧的不一致的中断系统。

它的工作原理如下:

  1. 希望使其方法可中断的程序员接受BreakFlag对象作为方法的参数。

  2. 在方法期间,程序员检查break_flag.is_set(),如果是,则退出并整理。

  3. 我们希望能够在对程序进行一些更改后,对break_flag.is_set()的所有原始调用保持相同的顺序。 (我们在一个调用的同一个循环中计算多个调用,因此不同大小的两个操作看起来是相同的)

    我们的第一种方法是使用调用堆栈来识别每个实例。例如,在代码中:

    void A(BreakFlag& flag) {
      flag.is_set();
      B(flag);
      C(flag);
    }
    
    void B(BreakFlag& flag) {
      flag.is_set();
      C(flag);
    }
    
    void C(BreakFlag& flag) {
      flag.is_set();
    }
    

    每次调用is_set时我们都会查看调用堆栈,并为此方法生成以下序列:

    A
    A, B
    A, B, C
    A, C
    

    然后我们可以使用它来检查每次测试程序时这个序列的检查器,以便有人不能出现并执行此操作:

    void A(BreakFlag& flag){       flag.is_set();       B(标志);       C(标志);     }

    void B(BreakFlag& flag) {
      flag.is_set();
      //C(flag); // I HAVE COMMENTED THIS OUT BECAUSE I DONT LIKE FLAG!
    }
    
    void C(BreakFlag& flag) {
      flag.is_set();
    }
    

    因为它会导致序列:

    A
    A, B
    A, C
    

    哪个与原版不匹配。

    我们遇到的问题是,编译器有时会以调用堆栈发生变化的方式进行优化,这会导致我们提出的系统注册错误的失败测试,​​因为调用堆栈不是它所期望的,即使它是对的。

    我们可以通过做类似以下的事情来解决它:

    #define CHECK_FLAG(x) actually_check_flag(__LINE__,__FILE__,x)
    

    这将允许我们基本上在代码中ID每个实例。

    除此之外,我们无法想出任何方式来识别每个对.is_set的调用,这些调用不会在光学代码中发生变化,是吗?

1 个答案:

答案 0 :(得分:1)

您可以使用RAII手动维护呼叫堆栈。在进入每个函数时构造一个保护对象:

void B(BreakFlag& flag) {
    BreakFlagStackGuard guard(flag, "B");
    flag.is_set();
    C(flag);
}

BreakFlagStackGuard的构造函数将函数名称"B"推送到flag.stack,而析构函数~BreakFlagStackGuard()(将在B返回时调用)会弹出它

无论编译器做什么来优化它都需要尊重你的保护对象,这样你就可以保证观察到的调用栈反映了源代码。