我有一个很久以前做的旧C++项目。它是一个CPU模拟器。每当代码中发生CPU故障(例如除以零、调试断点中断等)时,它只会执行throw
,在我的主循环中,我有类似这样的代码:
try{
*(uint32_t*)&op_cache=ReadDword(cCS,eip);
(this->*Opcodes[op_cache[0]])();
eip=(uint16_t)eip+1;
}
catch(CpuInt_excp err){
err.code&=0x00FF;
switch(err.code){
case 0:
case 1: //.....
Int16(err.code);
break;
default:
throw CpuPanic_excp("16bit Faults",(err.code|0xF000)|TRIPLE_FAULT_EXCP);
break;
}
}
以下是一个简单的操作码示例(凭空想象)
if(**regs16[AX]==0){
throw CpuInt_excp(0); //throw divide by zero error
}
这段代码的基本作用是读取一个操作码,如果发生异常,则调用相应的中断(在CPU中,这只是改变EIP)。
由于这个代码段位于主循环中,
try{}catch{}
的开销会不断累加。这并不是过早优化,我已经对其进行了剖析,gcc的异常帮助函数(甚至没有发生任何故障和抛出异常)和辅助函数占据了长时间运行的仿真程序总执行时间的10%以上。那么,在这种情况下,最好的替代异常的方法是什么呢?我宁愿不跟踪返回值,因为我已经编写了大量的代码,并且当函数变得非常深时,跟踪它们非常困难。
setjmp
和longjmp
,但这与许多C++特性不兼容。你可能不得不咬紧牙关,跟踪返回值,并从中吸取教训:异常是为了处理异常情况。 - ephemient