如果堆栈为空并且没有任何内容可以弹出,为什么std :: stack :: pop()不会抛出异常?
(我正在为自己的代码设计一个专用的堆栈,并且想知道这种方法的权衡(需要人们手动检查堆栈是否为空)而不是抛出异常。
我的猜测是,尽管C ++支持异常处理,但它带来了较小的运行时开销,因此,为了获得最大性能,决定不在std :: stack :: pop中引发异常。
答案 0 :(得分:12)
我认为pop()不必抛出异常 nothing 与效率或性能有关,但是 - 例外。
正如所说elsewhere:
SGI解释:http://www.sgi.com/tech/stl/stack.html 有人可能想知道为什么pop()会返回 void,而不是value_type。那是, 为什么必须使用top()和pop()来实现 检查并删除顶部元素, 而不是将两者结合在一起 单一成员功能?事实上,那里 是这个设计的一个很好的理由。如果 pop()返回顶部元素,它 必须以价值回报 而不是通过引用:通过引用返回 会创造一个悬垂的指针。 然而,按价值返回 效率低下:它涉及至少一个 冗余复制构造函数调用。以来 pop()不可能返回一个 价值以两者兼顾的方式 高效和正确,更多 明智的是它没有回报价值 所有并要求客户使用 top()检查顶部的值 堆栈。
- 醇>
std :: stack< T>是一个模板。如果pop()返回顶部元素,那么 必须以价值回报 而不是按照上述参考 说明。这意味着,在来电者 它必须在另一个T中复制 对象的类型。这涉及一份副本 构造函数或复制赋值 操作员电话。如果这个类型T是什么 足够复杂,它抛出一个 复制建设期间的例外或 复制作业?在那种情况下, rvalue,即堆栈顶部(返回 按价值而言,简直就是迷失了 没有其他方法可以从中检索它 堆栈作为堆栈的弹出操作 顺利完成!
一旦我们得出结论,pop应该不返回它弹出的元素,因此它的界面固定为void pop()
,它 - 这是我的意见 - 对任何意义都没有任何意义规定在空堆栈上调用pop()时会发生什么。
请注意,标准需要!empty()
作为调用pop()的前提条件。
UncleBens(在评论中)肯定有一点,即不在运行时检查前提条件(C ++标准AFAIK从未规定)具有一定的性能气味。但是,引用原始问题的一部分:(强调我的)
(我正在设计一个专门的Stack for 我自己的代码,想知道 与这种方法进行权衡(其中 需要一个人手动检查是否 堆栈是空的)与投掷 异常。
我会争辩说,pop()
没有返回任何东西的事实使得这个问题没有实际意义。它(恕我直言)根本没有意义强制pop()验证堆栈是否为空,当我们真的没有从它得到任何回报时(即如果堆栈是空的pop()可以简单地是一个noop ,(诚然)也没有由Std规定。)
我认为可以问为什么top()
不会抛出异常或可以问为什么pop()
不会返回顶部元素。如果pop
没有返回任何内容,抛出一个异常没有意义(在C ++世界中) - 声称它不会抛出异常“因为异常的运行时成本”就像其他答案一样意味着 - 恕我直言 - 错过了重点。
答案 1 :(得分:8)
你是对的。 C ++标准始终优先考虑性能和安全性。但是可能存在包含调试范围检查的STL实现。
答案 2 :(得分:5)
与C ++中的几乎所有功能一样,它们是围绕您不为不使用的内容付费的概念而设计的。并非所有环境都支持异常,传统上,尤其是游戏开发。
因此,如果使用std :: stack强制使用异常将失败其中一个设计指南。即使禁用了异常,您也希望能够使用堆栈。
答案 3 :(得分:3)
我认为值得一提的是,如果堆栈为空,pop()
允许抛出 - 它只是不需要。在你的堆栈中,你可以assert
堆栈不是空的,那就完全没问题了(空堆栈上的pop
似乎给了UB,所以你可以做任何你想做的事情,真)。
答案 4 :(得分:2)
除了性能之外,我不认为从空堆栈中弹出是一种特殊情况 - 因此我也不会抛弃它。
答案 5 :(得分:1)
例外是可选的,STL希望随处可用。认为嵌入式系统:许多C ++代码,运行时没有异常支持。