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

Pla*_*mer 21 c++ stack stl exception

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

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

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

Mar*_* Ba 14

我认为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(),它-这是我的观点-没有任何意义了规定时pop()方法被称为空栈上发生了什么.

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

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

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

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

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

  • 但是,我没有看到,如何选择不在运行时强制执行前置条件与性能以外的任何事情有关... (2认同)

Axe*_*ing 8

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

  • @Nathan:这些是为了异常安全而分开的.如果复制ctor在从按值返回的弹出返回时抛出,则您刚刚泄漏了堆栈顶部的项目(即,项目丢失,您也无法将其恢复到堆栈).见:http://www.gotw.ca/gotw/008.htm (11认同)

Dav*_*vid 6

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

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