Google C ++风格指南的无例外规则; STL?

时间:2011-03-03 17:16:17

标签: c++ exception stl

Google的C++ style guide说“我们不使用例外”。关于异常的使用,风格没有提到STL。由于STL分配器可能会失败,它们如何处理容器抛出的异常?

  1. 如果他们使用STL,呼叫者如何获知分配失败?像push_back()或地图operator[]这样的STL方法不会返回任何状态代码。
  2. 如果他们不使用STL,他们使用什么容器实现?

8 个答案:

答案 0 :(得分:53)

他们说他们不使用例外,而不是没人应该使用它们。如果你看一下理由,他们也会写:

  

由于Google的大多数现有C ++代码都没有准备好处理异常,因此采用生成异常的新代码相对比较困难。

通常的遗留问题。 : - (

答案 1 :(得分:42)

我们只是处理容器抛出的异常,至少在应用程序级代码中是这样。

自2008年以来,我一直是使用C ++工作的Google搜索的工程师。我们经常使用STL容器。我个人不记得曾经追溯到像vector :: push_back()或map :: operator []失败的单一主要故障或错误,我们说“哦,我们必须重写这段代码,因为分配可能失败“或”dang,如果我们只使用例外,这本来是可以避免的。“进程是否会耗尽内存?是的,但这通常是一个简单的错误(例如,有人向程序添加了一个大的新数据文件并忘记增加RAM分配)或者是没有好的方法来恢复和继续的灾难性故障。我们的系统已经自动管理和重新启动作业,以便对具有故障磁盘,宇宙射线等的机器提供强大的功能,这实际上并没有什么不同。

据我所知,这里没有问题。

答案 2 :(得分:11)

我很确定他们的意思是他们不会在他们的代码中使用例外。如果您查看他们的cpplint script,它会检查以确保您包含STL容器的正确标头(如矢量,列表等)。

答案 3 :(得分:6)

我发现Google明确提到了STL和异常(重点是我的):

  

虽然您不应在自己的代码中使用异常,但会使用它们   在ATL和一些STL中广泛使用,包括随之而来的   用Visual C ++。使用ATL时,您应该定义   _ATL_NO_EXCEPTIONS禁用异常。你应该调查是否   您也可以在STL中禁用异常,但如果没有,则为   单击确定以打开编译器中的异常。 (请注意,这只是为了   得到STL编译。 您仍然不应该编写异常处理   自己编码。

我不喜欢这样的决定(幸运的是我不是为谷歌工作),但他们对自己的行为和意图非常清楚。

答案 4 :(得分:6)

在现代操作系统上无论如何都无法处理分配失败;作为性能优化,它们通常会过度提交内存。例如,如果你在Linux上调用malloc()并要求一大块内存,它将成功,即使实际支持它所需的内存不存在。只有当你访问它时,内核才会真正尝试分配页面来支持它,那时告诉你分配失败已经太晚了。

所以:

  1. 除特殊情况外,不要担心分配失败。如果机器内存不足,那就是灾难性的失败,无法可靠地恢复。

  2. 尽管如此,抓住未处理的异常并记录e.what()输出然后重新throw是个好习惯,因为这可能比回溯更具信息性,而典型的C ++库实现不需要不会自动为你做这件事。

  3. 关于如何在内存不足时不能依赖崩溃的全部大线程是完整且彻底的垃圾。 C(++)标准可能无法保证,但现代系统崩溃的唯一的,如果内存不足,你可以依赖它。特别是,您不能依赖于从分配器获取NULL或任何其他指示,直到并包含C ++异常。

  4. 如果您发现自己位于可以访问页面零的嵌入式系统上,我强烈建议您通过在该位置映射无法访问的页面来解决此问题。不能依靠人类在任何地方检查NULL指针,但是您可以通过映射一次页面而不是尝试纠正每一个可能(过去,现在和< / em> future)有人可能错过NULL

  5. 的位置

    我将通过说你可能正在使用某种自定义分配器,或者你所处的系统没有过度提交(没有交换的嵌入式系统就是其中一个例子,但是不是唯一的例子)。在这种情况下,也许可以优雅地处理内存不足的情况,在你的系统上。但总的来说,在21世纪,我担心你不太可能有机会;第一个你知道你的系统内存不足就是事情开始崩溃的时候。

答案 5 :(得分:4)

Stl本身只是在内存分配失败的情况下直接抛出。但通常一个真实世界的应用程序可能由于各种原因而失败,内存分配失败只是其中之一。在32位系统上,内存分配失败不应该被忽略,因为它可能发生。所以上面关于内存分配失败不会发生的整个讨论都是毫无意义的。即使假设这样,也必须使用两步初始化来编写一个代码。而C ++异常处理早在64位架构之前就已存在。 我不确定我应该在多大程度上尊重谷歌所展示的负面专业精神,只回答问题。我记得1997年左右IBM发表的一篇论文,说明了IBM的一些人是如何理解的。赞赏C ++异常处理的含义。好的专业是没有必要的 成功的指标。 因此,如果使用STL,放弃异常处理不仅是一个问题。如果一个人使用C ++就是一个问题。这意味着放弃

  • 构造函数失败
  • 能够使用成员对象和基类对象作为以下任何基类/成员类构造函数的参数(无需任何测试)。毫无疑问,在C ++异常处理之前,人们使用了两步构造。
  • 放弃等级和&amp;在允许客户或第三方提供代码并抛出错误的环境中的丰富错误消息,调用代码的原始编写者在编写调用代码时无法预见,并且可能在返回错误时提供空间代码范围。
  • 避免将指向静态内存对象的指针返回给FlexLm的作者所做的消息分配失败
  • 能够使用内存分配器将地址返回到内存映射的稀疏文件中。在这种情况下,当一个人访问有问题的内存时会发生分配失败。(好的,目前这只适用于Windows,但是苹果强迫gnu团队在G ++编译器中提供必要的功能。需要来自Linux g ++开发人员的更多压力来提供这个功能也适合他们)(哎呀 - 这甚至适用于STL)
  • 能够将这种C风格编码留在我们身后(忽略返回值)并且必须使用带有调试可执行文件的调试器来查找在具有子进程和第三方提供的共享库或执行的非平凡环境中失败的内容远程执行
  • 能够将丰富的错误信息返回给调用者而无需将所有内容转储到stderr

答案 6 :(得分:2)

在问题中概述的假设下,只有一种可能性来处理分配失败:

  • 分配器强制应用程序退出分配失败。特别是,这需要cusror分配器。

索引越界异常在这种情况下不那么有趣, 因为申请可以确保他们使用预先检查不会发生。

答案 7 :(得分:1)

在这里晚了聚会,尽管我没有看到Google的C ++异常处理与Go中的异常处理之间的任何比较。具体来说,Go only has error handling通过内置的error类型。链接的Golang博客帖子明确结束了

正确的错误处理是好的软件的基本要求。通过使用本文中介绍的技术,您应该能够编写出更可靠和简洁的Go代码。

Golang的创建当然考虑了与C ++一起使用时的最佳实践。 underlying intuition is that less can be more。我没有在Google工作过,但确实发现他们使用C ++和创建Golang可能暗示着该公司的基本最佳实践。