简体   繁体   English

C ++ STL堆栈问题:如果堆栈为空,为什么pop()不会抛出异常?

[英]C++ STL stack question: Why does pop() not throw an exception if the stack is empty?

Why does std::stack::pop() not throw an exception if the stack is empty and there is nothing to pop? 为什么std :: stack :: pop()如果堆栈为空并且没有任何内容可以抛出异常?

(I'm designing a specialized Stack for my own code and would like to know the tradeoffs with this approach (which requires one to manually check if the stack is empty) vs. throwing an exception. (我正在为自己的代码设计一个专用的堆栈,并想知道这种方法的权衡(需要人们手动检查堆栈是否为空)而不是抛出异常。

My guess here would be that although C++ supports exception-handling, it comes with a small runtime overhead, and therefore, for maximum performance, the decision was made not to throw an exception in std::stack::pop). 我的猜测是,虽然C ++支持异常处理,但它带来了很小的运行时开销,因此,为了获得最大性能,决定不在std :: stack :: pop中抛出异常。

I would argue that the reason pop() doesn't have to throw an exception has nothing to do with efficiency or performance, but with - exceptions. 我认为pop()不必抛出异常的原因与效率或性能无关 ,而是与 - 例外。

As is argued elsewhere : 正如其他地方所说:

  1. SGI explanation: http://www.sgi.com/tech/stl/stack.html One might wonder why pop() returns void, instead of value_type. SGI解释: http//www.sgi.com/tech/stl/stack.html人们可能想知道为什么pop()返回void而不是value_type。 That is, why must one use top() and pop() to examine and remove the top element, instead of combining the two in a single member function? 也就是说,为什么必须使用top()和pop()来检查和删除顶部元素,而不是将两者组合在一个成员函数中? In fact, there is a good reason for this design. 事实上,这种设计有充分的理由。 If pop() returned the top element, it would have to return by value rather than by reference: return by reference would create a dangling pointer. 如果pop()返回顶部元素,则必须按值而不是按引用返回:按引用返回将创建一个悬空指针。 Return by value, however, is inefficient: it involves at least one redundant copy constructor call. 然而,按值返回是低效的:它涉及至少一个冗余复制构造函数调用。 Since it is impossible for pop() to return a value in such a way as to be both efficient and correct, it is more sensible for it to return no value at all and to require clients to use top() to inspect the value at the top of the stack. 由于pop()不可能以高效和正确的方式返回值,因此更不明智地返回任何值并要求客户端使用top()来检查值堆栈的顶部。

  2. std::stack < T > is a template. std :: stack <T>是一个模板。 If pop() returned the top element, it would have to return by value rather than by reference as per the of above explanation. 如果pop()返回顶部元素,则必须按值返回,而不是按照上述说明返回。 That means, at the caller side it must be copied in an another T type of object. 这意味着,在调用者端,它必须被复制到另一种T类型的对象中。 That involves a copy constructor or copy assignment operator call. 这涉及复制构造函数或复制赋值操作符调用。 What if this type T is sophisticated enough and it throws an exception during copy construction or copy assignment? 如果这种类型T足够复杂并且在复制构造或复制分配期间抛出异常怎么办? In that case, the rvalue, ie the stack top (returned by value) is simply lost and there is no other way to retrieve it from the stack as the stack's pop operation is successfully completed! 在这种情况下,rvalue,即堆栈顶部(由值返回)简单地丢失,并且没有其他方法可以从堆栈中检索它,因为堆栈的弹出操作已成功完成!

Once we conclude that pop should not return the element it pops and thus its interface is fixed as void pop() , it - this being my opinion - doesn't make any sense anymore to prescribe what happens when pop() is called on an empty stack. 一旦我们得出结论,流行应该回到它弹出,因此它的接口是固定的元素void pop() ,它-这是我的观点-没有任何意义了规定时弹出()被调用上发生了什么空堆栈。

Note that the standard requires !empty() as precondition for calling pop(). 请注意,标准要求使用!empty()作为调用pop()的前提条件。

UncleBens (in the comments) certainly has a point that not checking preconditions at runtime (which is never prescribed by the C++ std AFAIK) has a certain performance smell to it. UncleBens(在评论中)肯定有一点,即不在运行时检查前置条件(C ++ std AFAIK从未规定)具有一定的性能气味。 However, to quote part of the original question: (emphasis mine) 但是,引用原始问题的一部分:(强调我的)

(I'm designing a specialized Stack for my own code and would like to know the tradeoffs with this approach (which requires one to manually check if the stack is empty ) vs. throwing an exception. (我正在为自己的代码设计一个专用的堆栈,并想知道这种方法的权衡(需要人们手动检查堆栈是否为空 )而不是抛出异常。

I will argue, that the fact that pop() doesn't return anything renders the question moot. 我会争辩说, pop()不返回任何东西的事实使得这个问题没有实际意义。 It (IMHO) simply doesn't make sense to force pop() to validate if the stack is empty, when we really don't get anything back from it (ie if the stack would be empty pop() can simply be a noop, which is (admittedly) not prescribed by the Std either). 它(恕我直言)根本没有意义强制pop()验证堆栈是否为空,当我们真的没有从它得到任何回报时(即如果堆栈是空的pop()可以简单地是一个noop ,(诚然)也没有由Std规定)。

I think one can either ask why top() does not throw an exception or one can ask why pop() doesn't return the top element. 我想可以问为什么top()不会抛出异常, 或者可以问为什么pop()不返回top元素。 If pop doesn't return anything, throwing an exception doesn't make sense (in the C++ world) -- Claiming that it doesn't throw an exception "because of the runtime costs of exceptions" like other answers seem to imply is - IMHO - missing the point. 如果pop没有返回任何内容,抛出一个异常没有意义(在C ++世界中) - 声称它不会抛出异常“因为异常的运行时成本”,就像其他答案似乎暗示的那样 -恕我直言 - 错过了重点。

You are correct. 你是对的。 The C++ standard always prefers performance to safety. C ++标准始终优先考虑性能和安全性。 But there may be STL implementations that include debug range checks. 但是可能存在包括调试范围检查的STL实现。

As almost all features in C++, they are designed around the concept that you don't pay for what you don't use. 与C ++中的几乎所有功能一样,它们是围绕您不为不使用的内容付费的概念而设计的。 Not all environments support exceptions, traditionally, and most notably game development. 并非所有环境都支持异常,传统上,尤其是游戏开发。

So forcing the use of exceptions if you use std::stack would be failing one of the design guidelines. 因此,如果使用std :: stack,强制使用异常将失败其中一个设计指南。 You want to be able to use stack even if exceptions are disabled. 即使禁用了异常,您也希望能够使用堆栈。

I think it's worth mentioning that pop() is allowed to throw if the stack is empty -- it's just not required to. 我认为值得一提的是,如果堆栈为空,则允许 pop()抛出 - 这不是必需的。 In your stack, you could assert that the stack wasn't empty, and that would be perfectly fine ( pop on an empty stack seems to give UB, so you can do pretty much whatever you want, really). 在你的堆栈中,你可以assert堆栈不是空的,那就完全没问题了(在空堆栈上pop似乎给了UB,所以你可以做任何你想要的,真的)。

除了性能之外,我不认为从空堆栈中弹出是一种特殊情况 - 因此我也不会抛弃它。

exceptions are optional, and the STL wants to be available everywhere. 例外是可选的,STL希望随处可用。 think embedded systems: lots of C++ code, no exception support from runtimes. 认为嵌入式系统:许多C ++代码,运行时没有异常支持。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM