sea*_*ley 14 c++ performance exception
在C++ 0x中抛出异常有什么性能影响?这个编译器依赖多少?这与询问输入try块的成本是不一样的,即使没有抛出异常.
我们是否应该期望更多地使用异常来处理Java中的常规逻辑处理?
Ste*_*sop 36
#include <iostream>
#include <stdexcept>
struct SpaceWaster {
SpaceWaster(int l, SpaceWaster *p) : level(l), prev(p) {}
// we want the destructor to do something
~SpaceWaster() { prev = 0; }
bool checkLevel() { return level == 0; }
int level;
SpaceWaster *prev;
};
void thrower(SpaceWaster *current) {
if (current->checkLevel()) throw std::logic_error("some error message goes here\n");
SpaceWaster next(current->level - 1, current);
// typical exception-using code doesn't need error return values
thrower(&next);
return;
}
int returner(SpaceWaster *current) {
if (current->checkLevel()) return -1;
SpaceWaster next(current->level - 1, current);
// typical exception-free code requires that return values be handled
if (returner(&next) == -1) return -1;
return 0;
}
int main() {
const int repeats = 1001;
int returns = 0;
SpaceWaster first(1000, 0);
for (int i = 0; i < repeats; ++i) {
#ifdef THROW
try {
thrower(&first);
} catch (std::exception &e) {
++returns;
}
#else
returner(&first);
++returns;
#endif
}
#ifdef THROW
std::cout << returns << " exceptions\n";
#else
std::cout << returns << " returns\n";
#endif
}
Run Code Online (Sandbox Code Playgroud)
米老鼠基准测试结果:
$ make throw -B && time ./throw
g++ throw.cpp -o throw
1001 returns
real 0m0.547s
user 0m0.421s
sys 0m0.046s
$ make throw CPPFLAGS=-DTHROW -B && time ./throw
g++ -DTHROW throw.cpp -o throw
1001 exceptions
real 0m2.047s
user 0m1.905s
sys 0m0.030s
Run Code Online (Sandbox Code Playgroud)
所以在这种情况下,抛出1000个堆栈级别的异常,而不是正常返回,需要大约1.5ms.这包括进入try块,我相信某些系统在执行时是免费的,而其他系统在每次进入try时都会产生成本,而在其他系统上每次进入包含try的函数时只会产生成本.对于更可能的100个堆栈级别,我将重复次数增加到10k,因为一切都快了10倍.所以例外成本为0.1ms.
对于10000个堆栈级别,它是18.7秒vs 4.1s,因此异常大约需要14ms.因此,对于这个例子,我们正在研究每层堆栈1.5us的相当一致的开销(其中每个层正在破坏一个对象).
显然,C++ 0x没有指定异常的性能(或其他任何东西,除了算法和数据结构的大O复杂性).我不认为它会以一种严重影响许多实现的方式改变异常,无论是积极的还是消极的.
Bri*_*eal 14
异常性能非常依赖于编译器.您必须分析您的应用程序以查看它是否有问题.一般来说,它不应该.
你真的应该使用"异常条件"的例外,而不是一般的逻辑处理.例外是通过代码和错误路径分离正常路径的理想选择.
Mar*_*ork 10
我基本上认为问题是错误的.
什么是例外的成本是没有用的,更有用的是相对于备选的例外成本.因此,您需要测量多少异常成本并将其与返回错误代码进行比较>>>和<<<检查堆栈每个级别的错误代码展开.
另请注意,当您控制所有内容时,不应使用异常.在返回错误代码的类中,这可能是一种更好的技术.当您无法确定在运行时如何(或在何种上下文中)使用对象时,应使用异常来在运行时传输控制.
基本上它应该用于将控制转移到更高级别的上下文,其中具有足够上下文的对象将理解如何处理异常情况.
鉴于此用法原则,我们看到异常将用于在堆栈帧中传输控制多个级别.现在考虑编写所需的额外代码,以便将错误代码传递回同一个调用堆栈.考虑当错误代码可以来自多个不同方向并尝试协调所有不同类型的错误代码时添加的额外复杂性.
鉴于此,您可以看到异常如何能够极大地简化代码流,并且您可以看到代码流的复杂性.然后问题变成天气异常比需要在每个堆栈帧执行的复杂错误条件测试更昂贵.
答案始终取决于(如果您需要,请同时使用简介并使用速记).
但如果速度不是唯一的成本.
可维护性是可以衡量的成本.使用此成本度量异常总是获胜,因为它们最终使代码的控制流仅仅是需要完成的任务而不是任务和错误控制.
我曾经创建了一个x86仿真库,并使用异常中断等.馊主意.即使我没有抛出任何异常,它也会影响我的主循环.这样的事情是我的主要循环
try{
CheckInterrupts();
*(uint32_t*)&op_cache=ReadDword(cCS,eip);
(this->*Opcodes[op_cache[0]])();
//operate on the this class with the opcode functions in this class
eip=(uint16_t)eip+1;
}
//eventually, handle these and do CpuInts...
catch(CpuInt_excp err){
err.code&=0x00FF;
switch(err.code){
Run Code Online (Sandbox Code Playgroud)
在try块中包含该代码的开销使得异常函数成为CPU时间前5位用户中的2位.
那对我来说很贵
没有理由为什么C++ 0x中的异常应该比C++ 03更快或更慢.这意味着他们的表现完全取决于实施.Windows使用完全不同的数据结构来实现32位与64位以及Itanium与x86之间的异常处理.Linux并不能保证只使用一个实现.这取决于.有几种流行的方法来实现异常处理,所有这些方法都有优点和缺点.
所以它不依赖于语言(c ++ 03 vs 0x),而是依赖于编译器,运行时库,操作系统和CPU架构.