首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么C++中没有“最终”结构?

为什么C++中没有“最终”结构?
EN

Software Engineering用户
提问于 2013-05-09 17:08:34
回答 7查看 57.8K关注 0票数 67

C++中的异常处理仅限于尝试/抛出/捕捉。与对象Pascal、Java、C#和Python不同,即使在C++ 11中,finally构造也没有实现。

我看到了很多关于“异常安全代码”的C++文献。利普曼写道,异常安全代码是一个重要但高级的、困难的话题,超出了他的Primer的范围-这似乎意味着安全代码不是C++的基础。赫伯萨特花了10章在他的例外的C++的主题!

然而,在我看来,如果实现了finally构造,那么在试图编写“异常安全代码”时遇到的许多问题可能会得到很好的解决,这样程序员就可以确保即使出现异常,程序也可以恢复到安全、稳定、无泄漏的状态,接近资源分配点和潜在的问题代码。作为一个非常有经验的德尔菲和C#程序员,我使用了..。最后,与大多数使用这些语言的程序员一样,我的代码中也有相当广泛的阻塞。

考虑到所有在C++ 11中实现的“铃铛和口哨”,我惊讶地发现“终于”还没有出现。

那么,为什么finally构造从未在C++中实现过呢?它并不是一个非常困难或高级的概念,它可以帮助程序员编写“异常安全代码”。

EN

回答 7

Software Engineering用户

回答已采纳

发布于 2013-05-09 18:05:41

这实际上只是一个理解C++的哲学和习语的问题。以您的操作为例,该操作将在持久类上打开数据库连接,并必须确保如果引发异常,该操作将关闭该连接。这是一个异常安全的问题,适用于任何有异常的语言(C++、C#、Delphi.l.)。

在使用try / finally的语言中,代码可能如下所示:

代码语言:javascript
复制
database.Open();
try {
    database.DoRiskyOperation();
} finally {
    database.Close();
}

简单直截了当。然而,也有一些缺点:

  • 如果语言没有确定性析构函数,我总是必须编写finally块,否则就会泄漏资源。
  • 如果DoRiskyOperation不仅仅是一个方法调用--如果我在try块中有一些处理要做--那么Close操作最终可能会与Open操作相去甚远。我不能把我的清理写在我的收购案旁边。
  • 如果我有几个需要获得的资源,然后以异常安全的方式释放,那么我最终可以得到几层深度的try / finally块。

C++方法如下所示:

代码语言:javascript
复制
ScopedDatabaseConnection scoped_connection(database);
database.DoRiskyOperation();

这完全解决了finally方法的所有缺点。它本身有几个缺点,但它们相对较小:

  • 您很可能需要自己编写ScopedDatabaseConnection类。然而,这是一个非常简单的实现--只有4或5行代码。
  • 它涉及到创建一个额外的局部变量--显然您并不喜欢这个变量,因为您的评论是“不断地创建和销毁类以依赖它们的析构函数来清理您的混乱”--但是一个好的编译器会优化额外局部变量所涉及的任何额外工作。良好的C++设计很大程度上依赖于这类优化。

就我个人而言,考虑到这些优点和缺点,我发现RAII (资源获取是初始化)是一种比finally更好的技术。你的里程可能会不同。

最后,由于RAII在C++中是一个非常成熟的成语,并且为了减轻开发人员编写大量Scoped...类的负担,有一些库(如ScopeGuardBoost.ScopeExit )为这种确定性清理提供了便利。

票数 60
EN

Software Engineering用户

发布于 2013-05-09 17:14:42

来自为什么C++不提供一个“最终”结构?在……C++风格和技术常见问题里面Bjarne Stroustrup

因为C++支持一种几乎总是更好的替代方法:“资源获取就是初始化”技术(TC++PL3第14.4节)。基本思想是用本地对象表示资源,以便本地对象的析构函数释放资源。这样,程序员就不会忘记释放资源。

票数 59
EN

Software Engineering用户

发布于 2013-05-09 17:24:04

C++没有finally的原因是因为在C++中不需要它。finally用于执行某些代码,而不管是否发生了异常,这几乎总是某种类型的清理代码。在C++中,这个清理代码应该位于相关类的析构函数中,并且析构函数将始终被调用,就像finally块一样。使用析构函数进行清理的成语称为雷伊

在C++社区中,可能会有更多关于“异常安全”代码的讨论,但在其他有异常的语言中,这几乎是同样重要的。“异常安全”代码的全部要点是,如果在调用的任何函数/方法中发生异常,则您会考虑代码处于何种状态。

在C++中,‘异常安全’代码稍微重要一些,因为C++没有自动垃圾收集来处理由于异常而成为孤儿的对象。

在C++社区中更多地讨论异常安全的原因可能也源于这样一个事实:在C++中,您必须更多地意识到可能出错的地方,因为语言中的默认安全网较少。

票数 20
EN
页面原文内容由Software Engineering提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://softwareengineering.stackexchange.com/questions/197562

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档