繁体   English   中英

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

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

为什么std :: stack :: pop()如果堆栈为空并且没有任何内容可以抛出异常?

(我正在为自己的代码设计一个专用的堆栈,并想知道这种方法的权衡(需要人们手动检查堆栈是否为空)而不是抛出异常。

我的猜测是,虽然C ++支持异常处理,但它带来了很小的运行时开销,因此,为了获得最大性能,决定不在std :: stack :: pop中抛出异常。

我认为pop()不必抛出异常的原因与效率或性能无关 ,而是与 - 例外。

正如其他地方所说:

  1. SGI解释: http//www.sgi.com/tech/stl/stack.html人们可能想知道为什么pop()返回void而不是value_type。 也就是说,为什么必须使用top()和pop()来检查和删除顶部元素,而不是将两者组合在一个成员函数中? 事实上,这种设计有充分的理由。 如果pop()返回顶部元素,则必须按值而不是按引用返回:按引用返回将创建一个悬空指针。 然而,按值返回是低效的:它涉及至少一个冗余复制构造函数调用。 由于pop()不可能以高效和正确的方式返回值,因此更不明智地返回任何值并要求客户端使用top()来检查值堆栈的顶部。

  2. std :: stack <T>是一个模板。 如果pop()返回顶部元素,则必须按值返回,而不是按照上述说明返回。 这意味着,在调用者端,它必须被复制到另一种T类型的对象中。 这涉及复制构造函数或复制赋值操作符调用。 如果这种类型T足够复杂并且在复制构造或复制分配期间抛出异常怎么办? 在这种情况下,rvalue,即堆栈顶部(由值返回)简单地丢失,并且没有其他方法可以从堆栈中检索它,因为堆栈的弹出操作已成功完成!

一旦我们得出结论,流行应该回到它弹出,因此它的接口是固定的元素void pop() ,它-这是我的观点-没有任何意义了规定时弹出()被调用上发生了什么空堆栈。

请注意,标准要求使用!empty()作为调用pop()的前提条件。

UncleBens(在评论中)肯定有一点,即不在运行时检查前置条件(C ++ std AFAIK从未规定)具有一定的性能气味。 但是,引用原始问题的一部分:(强调我的)

(我正在为自己的代码设计一个专用的堆栈,并想知道这种方法的权衡(需要人们手动检查堆栈是否为空 )而不是抛出异常。

我会争辩说, pop()不返回任何东西的事实使得这个问题没有实际意义。 它(恕我直言)根本没有意义强制pop()验证堆栈是否为空,当我们真的没有从它得到任何回报时(即如果堆栈是空的pop()可以简单地是一个noop ,(诚然)也没有由Std规定)。

我想可以问为什么top()不会抛出异常, 或者可以问为什么pop()不返回top元素。 如果pop没有返回任何内容,抛出一个异常没有意义(在C ++世界中) - 声称它不会抛出异常“因为异常的运行时成本”,就像其他答案似乎暗示的那样 -恕我直言 - 错过了重点。

你是对的。 C ++标准始终优先考虑性能和安全性。 但是可能存在包括调试范围检查的STL实现。

与C ++中的几乎所有功能一样,它们是围绕您不为不使用的内容付费的概念而设计的。 并非所有环境都支持异常,传统上,尤其是游戏开发。

因此,如果使用std :: stack,强制使用异常将失败其中一个设计指南。 即使禁用了异常,您也希望能够使用堆栈。

我认为值得一提的是,如果堆栈为空,则允许 pop()抛出 - 这不是必需的。 在你的堆栈中,你可以assert堆栈不是空的,那就完全没问题了(在空堆栈上pop似乎给了UB,所以你可以做任何你想要的,真的)。

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

例外是可选的,STL希望随处可用。 认为嵌入式系统:许多C ++代码,运行时没有异常支持。

暂无
暂无

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

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