多年来一直在做Java,所以一直没有跟踪C++.已经最后条款中增加了C++异常处理的语言定义是什么?
是否有一种模仿Java的尝试/终极的青睐成语?
我还担心C++没有可能抛出的所有可能异常的最终超类型 - 比如Java的Throwable类.
我可以写:
try { // do something } catch(...) { // alas, can't examine the exception // can only do cleanup code and perhaps rethrow, ala: throw; }
附录编辑:
我最终接受了得票最多的答案,即使用析构函数进行清理.当然,从我自己的评论来看,很明显我并不完全同意这一点.但是,C++就是这样,所以在我想到的应用程序中,我会或多或少地努力坚持共同的社区实践.我将使用模板类来包装尚未具有类析构函数的资源(即C库资源),从而赋予它们析构函数语义.
新的附加编辑:
嗯,而不是最后一个封闭功能或许?结合ScopeGuard方法的闭包(参见下面的答案之一)将是一种通过任意操作完成清理并访问清理代码的外部范围上下文的方法.清理可以用在Ruby编程中看到的成语方式来完成,它们在打开资源时提供清理块.C++不考虑关闭功能吗?
Jason Baker.. 26
通过有效地使用析构函数.当在try块中抛出异常时,在其中创建的任何对象将立即被销毁(因此它的析构函数被调用).
这与Java不同,您不知道何时调用对象的终结器.
更新:直接从马口: 为什么C++不能提供"最终"结构?
通过有效地使用析构函数.当在try块中抛出异常时,在其中创建的任何对象将立即被销毁(因此它的析构函数被调用).
这与Java不同,您不知道何时调用对象的终结器.
更新:直接从马口: 为什么C++不能提供"最终"结构?
我的$ .02.我多年来一直使用C#和Java等托管语言进行编程,但为了提高速度,我们不得不切换到C++.起初我无法相信我必须在头文件和cpp文件中两次写出方法签名,我不喜欢没有finally块,并且没有垃圾收集意味着跟踪内存泄漏到处 - 天哪,我根本不喜欢它!
但是,正如我所说,我被迫使用C++.所以我被迫认真学习它,现在我终于理解了所有的编程习语,比如RAII,我得到了语言的所有细微之处等等.我花了一段时间,但现在我看到它与C#或Java相比有多么不同.
这些天我觉得C++是最好的语言!是的,我可以理解,有时我会称之为"糠"(看似不必要的东西),但在真正认真地使用这种语言之后,我已经彻底改变了我的想法.
我曾经一直有内存泄漏.我以前把我的所有代码写入.h文件,因为我讨厌代码的分离,我不明白为什么他们会这样做!而我以前总是以愚蠢的循环包含依赖关系结束,并且更多.我真的很喜欢C#或Java,对我而言,C++是一个巨大的进步.这些天我明白了.我几乎从来没有内存泄漏,我喜欢界面和实现的分离,我不再有循环依赖的问题.
而且我也不会错过finally块.说实话,我的观点是,你谈到在catch块中编写重复清理操作的这些C++程序员对我来说只是听起来像是他们只是糟糕的C++程序员.我的意思是,它看起来不像这个线程中的任何其他C++程序员都有你提到的任何问题.RAII确实最终变得多余,如果有的话,它的工作就更少了.你写了一个析构函数,然后你永远不必写另一个!至少对于那种类型.
尊重,我认为你现在只是习惯了Java,就像我以前一样.
C++的答案是RAII:对象的析构函数将在超出范围时执行.无论是回归,异常还是其他.如果你在其他地方处理异常,你可以确保调用析构函数调用从被调用函数到你的处理程序的所有对象都会被正确地破坏.他们会为你清理.
阅读http://en.wikipedia.org/wiki/Resource_acquisition_is_initialization
最后没有添加到C++,也不可能添加.
C++使用构造函数/析构函数的方式使得最终不需要.
如果您使用catch(...)进行清理,那么您没有正确使用C++.清理代码应该都在析构函数中.
虽然不要求使用它,但C++确实有一个std :: exception.
强制开发人员从特定类派生以使用异常违背了保持简单的C++哲学.这也是我们不要求所有类派生自Object的原因.
阅读:C++是否支持'finally'块?(我听到的'RAII'是什么?)
finally的使用比析构函数更容易出错.
这是因为你强迫对象的用户进行清理而不是类的设计者/实现者.
好的,我必须在一个单独的答案帖子中添加一个答案:(如果你把它编辑成原始问题会更方便,所以它不会在下面的底部结束它的答案.
如果所有清理总是在析构函数中完成,那么就不需要在catch块中有任何清理代码 - 但是C++有catch块来完成清理操作.实际上它有一个catch(...)块,它只能进行清理操作(当然,无法获取任何异常信息来进行任何日志记录).
catch具有完全独立的目的,作为Java程序员,您应该意识到这一点.finally子句用于"无条件"清理操作.无论块如何退出,都必须这样做.Catch用于条件清理.如果抛出此类异常,我们需要执行一些额外的操作.
无论是否抛出异常,finally块中的清理都将完成 - 这是清理代码存在时总是想要发生的事情.
真?如果我们希望它总是发生在这种类型上(比如,我们总是希望在完成它时关闭数据库连接),那么为什么我们不定义它一次呢?在类型本身?使数据库连接自身关闭,而不是每次使用它时都要尝试/终止它?
这是析构函数中的重点.它们保证每种类型都能够在每次使用时都能够自行清理,而不需要调用者进行清理.
从第一天开始,C++开发人员一直困扰着必须重复清理操作,这些操作出现在成功退出try块时发生的代码流中的catch块中.Java和C#程序员只需在finally块中执行一次.
没有.C++程序员从未受到过这样的困扰.C程序员有.并且C程序员意识到c ++有类,然后称自己为C++程序员.
我每天用C++和C#编程,我觉得我被C#的荒谬坚持所困扰,我必须提供一个finally子句(或using
块)每一次我都使用数据库连接或其他必须清理的东西.
C++允许我一劳永逸地指定"每当我们完成这种类型时,它应该执行这些操作".我不冒险忘记释放记忆.我不冒险忘记关闭文件句柄,套接字或数据库连接.因为我的内存,我的句柄,套接字和数据库连接都是自己做的.
它怎么能永远是最好有在每次使用类型时间写重复的清理代码?如果你需要包装类型,因为它本身没有析构函数,你有两个简单的选择:
寻找一个适当的C++库来提供这个析构函数(提示:Boost)
使用boost :: shared_ptr来包装它,并在运行时为它提供一个自定义函子,指定要完成的清理.
当您编写像Java EE应用程序服务器Glassfish,JBoss等应用程序服务器软件时,您希望能够捕获并记录异常信息 - 而不是让它落在地板上.或者更糟糕的是落入运行时并导致应用程序服务器的非常突然退出.这就是为什么要为任何可能的异常提供一个总体基类是非常可取的.而C++就是这样一个类.的std ::例外.
自从CFront时代以及Java/C#这十年来的大部分时间都做过C++.很明显,在如何处理基本类似的事情方面存在巨大的文化差距.
不,你从来没有做过C++.你已经完成了CFront,或C课程.不是C++.这是一个巨大的差异.退出调用答案蹩脚,你可能会学到一些你认为你知道的语言.;)
清理功能本身就完全是蹩脚的.它们具有较低的凝聚力,因为它们预计会执行一系列仅在它们发生时才相关的活动.它们具有高耦合性,因为当实际执行某些操作的功能发生变化时,它们需要对其内部进行修改.因此,它们容易出错.
try ... finally构造是一个清理函数的框架.这是一种语言鼓励的方式来编写糟糕的代码.此外,由于它鼓励一遍又一遍地编写相同的清理代码,因此破坏了DRY原则.
对于这些目的,C++方式更为可取.在析构函数中,资源的清理代码只写入一次.它与该资源的其余代码位于同一位置,因此具有良好的凝聚力.清理代码不必放入不相关的模块中,因此减少了耦合.精心设计时,它只写一次.
而且,C++方式更加统一.C++,随着智能指针的添加,以相同的方式处理各种资源,而Java处理内存并提供不足的构造来释放其他资源.
C++有很多问题,但这不是其中之一.有些方法Java比C++更好,但这不是其中之一.
使用实现RAII而不是尝试最终的方法,Java会好得多.