NULL 与 throw 和性能
我有一个类:
class Vector {
public:
element* get(int i);
private:
element* getIfExists(int i):
};
get
调用getIfExists
;如果元素存在,则返回该元素,如果不存在,则执行某些操作。 getIfExists
可以表明某些元素 i
不存在 要么抛出异常,要么返回 NULL。
问:性能上会有什么不同吗?在一种情况下,get
需要检查==NULL
,在另一种情况下try...catch
。
I have a class:
class Vector {
public:
element* get(int i);
private:
element* getIfExists(int i):
};
get
invokes getIfExists
; if element exists, it is returned, if not, some action is performed. getIfExists
can signal that some element i
is not present
either by throwing exception, or by returning NULL.
Question: would there be any difference in performance? In one case, get
will need to check ==NULL
, in another try... catch
.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
这是设计问题,而不是性能问题。如果出现异常情况(例如在
get
函数中),则抛出异常;或者甚至更好地触发断言,因为违反函数前提条件是编程错误。如果它是预期的情况 - 就像您的getIfExist
函数一样 - 那么不要抛出异常。关于性能,存在零成本异常实现(尽管并非所有编译器都使用该策略)。这意味着只有在抛出异常时才会支付开销,这应该是……嗯……例外。
Its a matter of design, not performance. If its an exceptional situation -like in your
get
function- then throw an exception; or even better fire an assert since violation of a function precondition is a programming error. If its an expected case -like in yourgetIfExist
function- then don't throw an exception.Regarding performance, zero cost exception implementations exist (although not all compilers use that strategy). This means that the overhead is only paid when an exception its thrown, which should be... well... exceptionally.
现代编译器实现“零成本”异常 - 它们仅在抛出时产生成本,并且成本与清理加上清理列表的缓存未命中成正比。因此,如果异常是异常的,它们确实可以比返回码更快。如果它们没有异常,它们可能会更慢。如果你的错误是在函数调用中的函数中的函数中,那么它实际上所做的工作要少得多。细节很有趣,非常值得谷歌搜索。
但成本非常微薄。在一个紧密的循环中,它可能会产生影响,但通常不会。
您应该编写最容易推理和维护的代码,然后分析它,并仅在出现瓶颈时重新审视您的决定。
Modern compilers implement 'zero cost' exceptions - they only incur cost when thrown, and the cost is proportional to the cleanup plus the cache-miss to get the list to clean up. Therefore, if exceptions are exceptional, they can indeed be faster than return-codes. And if they are unexceptional, they may be slower. And if your error is in a function in a function in a function call, it actually do much less work throwing. The details are fascinating and well worth googling.
But the cost is very marginal. In a tight loop it might make a difference, but generally not.
You should write the code that is easiest to reason about and maintain, and then profile it and revisit your decision only if its a bottleneck.
(请参阅评论!)
毫无疑问,
return NULL
变体具有更好的性能。当也可以使用返回值时,您通常不应该使用异常。
由于该方法名为
get
我认为 NULL 不是有效的结果值,因此传递 NULL 应该是最好的解决方案。如果调用者不测试结果值,它会取消引用空值,呈现 SIGSEGV,这也是合适的。
如果该方法很少被调用,那么您根本不应该关心微观优化。
您认为哪种翻译方法更容易?
$ g++ -Os -c test.cpp
$ objdump -dC test.o
(See comments!)
Without a doubt the
return NULL
variant has a better performance.You should mostly never use exceptions when using return values is possible too.
Since the method is named
get
I assume NULL won't be a valid result value, so passing NULL should be the best solution.If the caller does not test the result value, it dereferences a null value, rendering a SIGSEGV, what is appropriate too.
If the method is rarely called, you should not care about micro optimizations at all.
Which translated method looks easier to you?
$ g++ -Os -c test.cpp
$ objdump -dC test.o
性能肯定会有差异(如果你给
Vector::getIfExists
一个throw()
规范,甚至可能会有很大的差异,但我在这里推测一下)。但在我看来,这是只见树木不见森林。金钱问题是:您是否要使用越界参数多次调用此方法?如果是,为什么?
There will certainly be a difference in performance (maybe even a very big one if you give
Vector::getIfExists
athrow()
specification, but I 'm speculating a bit here). But IMO that's missing the forest for the trees.The money question is: are you going to call this method so many times with an out-of-bounds parameter? And if yes, why?
是的,性能上会有差异:返回 NULL 比抛出异常便宜,检查 NULL 比捕获异常便宜。
附录:但是,只有当您预计这种情况会频繁发生时,性能才有意义,在这种情况下,无论如何,它可能都不是例外情况。在 C++ 中,使用异常来实现正常的程序逻辑被认为是不好的风格,这似乎是:我假设
get
的目的是在必要时自动扩展向量?Yes, there would be a difference in performance: returning NULL is less expensive than throwing an exception, and checking for NULL is less expensive than catching an exception.
Addendum: But performance is only relevant if you expect that this case will happen frequently, in which case it's probably not an exceptional case anyway. In C++, it's considered bad style to use exceptions to implement normal program logic, which this seems to be: I'm assuming that the point of
get
is to auto-extend the vector when necessary?如果调用者希望处理某个项目不存在的可能性,您应该以一种表明这一点的方式返回,而不抛出异常。如果调用者没有做好准备,您应该抛出异常。当然,被调用的例程不可能神奇地知道调用者是否准备好迎接麻烦。需要考虑的几种方法:
在实践中,我倾向于经常使用#2。我不喜欢#1,因为我觉得函数的返回值应该与其主要目的相符。
If the caller is going to be expecting to deal with the possibility of an item not existing, you should return in a way that indicates that without throwing an exception. If the caller is not going to be prepared, you should throw an exception. Of course, the called routine isn't likely to magically know whether the caller is prepared for trouble. A few approaches to consider:
In practice, I tend to use #2 a lot. I dislike #1, since I feel that the return value of a function should correspond with its primary purpose.