1

我们正在开发一种新的中断系统(在 c++ 中),以取代旧的不一致的系统。

它是这样工作的:

  1. 想要使他的方法可中断的程序员接受一个BreakFlag对象作为该方法的参数。

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

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

然后我们可以使用它来检查每次我们测试程序时是否发生了这个检查序列,这样就不会有人来做这个:

无效 A(BreakFlag& 标志) { 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)

这将允许我们在代码中识别每个实例。

除此之外,我们想不出任何方法来识别每个调用.is_set不会在优化代码中改变,你可以吗?

4

1 回答 1

1

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

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

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

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

于 2012-08-16T14:52:56.250 回答