C++中的异常处理仅限于尝试/抛出/捕捉。与对象Pascal、Java、C#和Python不同,即使在C++ 11中,finally构造也没有实现。
我看到了很多关于“异常安全代码”的C++文献。利普曼写道,异常安全代码是一个重要但高级的、困难的话题,超出了他的Primer的范围-这似乎意味着安全代码不是C++的基础。赫伯萨特花了10章在他的例外的C++的主题!
然而,在我看来,如果实现了finally构造,那么在试图编写“异常安全代码”时遇到的许多问题可能会得到很好的解决,这样程序员就可以确保即使出现异常,程序也可以恢复到安全、稳定、无泄漏的状态,接近资源分配点和潜在的问题代码。作为一个非常有经验的德尔菲和C#程序员,我使用了..。最后,与大多数使用这些语言的程序员一样,我的代码中也有相当广泛的阻塞。
考虑到所有在C++ 11中实现的“铃铛和口哨”,我惊讶地发现“终于”还没有出现。
那么,为什么finally构造从未在C++中实现过呢?它并不是一个非常困难或高级的概念,它可以帮助程序员编写“异常安全代码”。
发布于 2013-05-09 18:05:41
这实际上只是一个理解C++的哲学和习语的问题。以您的操作为例,该操作将在持久类上打开数据库连接,并必须确保如果引发异常,该操作将关闭该连接。这是一个异常安全的问题,适用于任何有异常的语言(C++、C#、Delphi.l.)。
在使用try / finally的语言中,代码可能如下所示:
database.Open();
try {
database.DoRiskyOperation();
} finally {
database.Close();
}简单直截了当。然而,也有一些缺点:
finally块,否则就会泄漏资源。DoRiskyOperation不仅仅是一个方法调用--如果我在try块中有一些处理要做--那么Close操作最终可能会与Open操作相去甚远。我不能把我的清理写在我的收购案旁边。try / finally块。C++方法如下所示:
ScopedDatabaseConnection scoped_connection(database);
database.DoRiskyOperation();这完全解决了finally方法的所有缺点。它本身有几个缺点,但它们相对较小:
ScopedDatabaseConnection类。然而,这是一个非常简单的实现--只有4或5行代码。就我个人而言,考虑到这些优点和缺点,我发现RAII (资源获取是初始化)是一种比finally更好的技术。你的里程可能会不同。
最后,由于RAII在C++中是一个非常成熟的成语,并且为了减轻开发人员编写大量Scoped...类的负担,有一些库(如ScopeGuard和Boost.ScopeExit )为这种确定性清理提供了便利。
发布于 2013-05-09 17:14:42
来自为什么C++不提供一个“最终”结构?在……C++风格和技术常见问题里面Bjarne Stroustrup:
因为C++支持一种几乎总是更好的替代方法:“资源获取就是初始化”技术(TC++PL3第14.4节)。基本思想是用本地对象表示资源,以便本地对象的析构函数释放资源。这样,程序员就不会忘记释放资源。
发布于 2013-05-09 17:24:04
C++没有finally的原因是因为在C++中不需要它。finally用于执行某些代码,而不管是否发生了异常,这几乎总是某种类型的清理代码。在C++中,这个清理代码应该位于相关类的析构函数中,并且析构函数将始终被调用,就像finally块一样。使用析构函数进行清理的成语称为雷伊。
在C++社区中,可能会有更多关于“异常安全”代码的讨论,但在其他有异常的语言中,这几乎是同样重要的。“异常安全”代码的全部要点是,如果在调用的任何函数/方法中发生异常,则您会考虑代码处于何种状态。
在C++中,‘异常安全’代码稍微重要一些,因为C++没有自动垃圾收集来处理由于异常而成为孤儿的对象。
在C++社区中更多地讨论异常安全的原因可能也源于这样一个事实:在C++中,您必须更多地意识到可能出错的地方,因为语言中的默认安全网较少。
https://softwareengineering.stackexchange.com/questions/197562
复制相似问题