【CSDN 编者按】一直以来,C 和 C++ 都是非常优秀的编程语言不过,两种语言虽名称有些相似,但应用场景存在巨大的不同对于 C 语言而言,其主要被用于操作系统、容器、物联网、数据库等领域的开发,而 C++ 则是开发桌面软件、图形处理、游戏、网站的最佳工具。
在本文中,作者原以为 C++ 在开发基础设施时会更胜一筹,然而经过与 C 语言的尝试对比,发现事实并非如此原文链接:https://250bpm.com/blog:4/?continueFlag=c778b3c9525d12a012a35269d830ebcc
声明:本文为 CSDN 翻译,转载需注明来源作者 | Martin Sústrik 译者 | 弯月 责编 | 屠敏出品 | CSDN(ID:CSDNnews)以下为翻译正文:。
首先声明,在整个职业生涯中,我一直在使用C++,而且在做大多数项目时,C++仍然是我的首选语言因此,在开始构建个人项目ZeroMQ(可伸缩的分布式或并发应用程序设计的高性能异步消息库)时,我也选用了C++,主要原因如下:。
C++包含一些数据结构和算法库如果使用C语言,我将不得不依赖第三方库,或者自己动手编写基本算法C++会强制我在编程风格上保持一些基本的统一性例如,this参数不允许使用几种不同的机制将指针传递给正在处理的对象,而这个问题在C项目中很常见。
同样,不可以明确将成员变量标记为私有,此外还有C++的一些其他特征使用C语言实现虚函数非常复杂,会导致理解和管理代码的难度加剧不过,严格来说,这个问题其实是上一个问题的一个子集,但我觉得有必要单独指出最后,每个人都喜欢在代码的末尾自动调用析构函数。
然而,事到如今,我不得不承认C++是一个糟糕的选择下面,我来解释一下原因首先,我的个人项目ZeroMQ是一个持续运行的基础设施,永远不应该出故障,永远不应该表现出未定义的行为因此,错误处理至关重要,必须做到明确且严格。
然而,C++的异常处理并不能满足我的需求如果程序不会出错,那么选择C++没有任何问题,只需将main函数包装在try/catch中,集中在一个地方处理所有错误如果你的目标是保证不会出现未定义的行为,那么C++的异常处理就会变成一场噩梦。
由于C++解耦了异常的发生与处理,因此错误处理非常容易,但也造成了你几乎不可能保证程序永远不会运行未定义的行为在C语言中,错误的产生和处理是紧密结合的,在同一块源代码中因此,在出错时很容易理解发生了什么:。
int rc = fx ();if (rc != 0)handle_error ();而在C++中,你只能抛出错误,却不清楚究竟发生了什么:int rc = fx ();if (rc != 0)throw std::exception ();
问题在于,你并不清楚在哪里处理异常处理错误的代码在同一个函数中会更加方便理解,尽管不太方便阅读:try {…int rc = fx ();if (rc != 0)throw std::exception (“Error!”);…catch (std::exception &e) {handle_exception ();}。
然而,我们来考虑同一个函数抛出两个不同的错误,结果会怎么样:class exception1 {};class exception2 {};try {…if (condition1)throw my_exception1 ();…if (condition2)throw my_exception2 ();…}catch (my_exception1 &e) {handle_exception1 ();}catch (my_exception2 &e) {handle_exception2 ();}
以下是等效的C代码:…if (condition1)handle_exception1 ();…if (condition2)handle_exception2 ();…相较之下,C语言更加方便阅读,而且编译器也会生成更高效的代码。
然而,C++的问题还不仅限于此考虑某个函数会引发异常,但不会处理异常的情况在这种情况下,错误的处理可以放到任何地方,具体取决于从哪里调用该函数针对不同的情况,采用不同的方式处理异常?这种方法听起来似乎很有道理,但很快就会变成一场噩梦。
在修复某个Bug时,你会发现许多其他地方也有相同的Bug,因为它们都复制了同一段错误处理代码每当添加一个函数调用,就有可能增加一个新异常,如果调用函数的代码没有妥善处理该异常,就意味着增加了一个新Bug。
如果你还想坚持“没有未定义的行为”原则,就不得不引入新异常,以便区分不同的故障模式但是,添加新异常就意味着,它会上升到不同的地方你必须在所有地方添加相应的异常处理,否则就会出现未定义的行为看到这里,你可能想说:这就是异常的正确用法啊?。
然而问题在于,异常只是一个工具,目的是用更系统的方式管理呈现指数增长的错误处理代码,但它并不能解决根本的问题甚至可以说,异常有可能导致情况恶化,因为你不仅需要编写新的异常类型,还需要针对新类型编写异常处理代码。
考虑到上述问题,我决定使用C++,但不使用异常如今我的这个项目就是这样实现的不幸的是,问题并没有就此止步……考虑一下,如果对象的初始化失败,会发生什么?构造函数没有返回值,因此只能通过抛出异常来报告失败。
但是,我决定不使用异常所以,我们必须像下面这样处理:class foo{public:foo ();int init ();…};在创建实例时,会调用构造函数(这个函数不会失败),然后调用init函数(这个函数可能会失败)。
与C语言相比,C++代码更复杂:struct foo{…};int foo_init (struct foo *self);然而,C++代码真正的问题在于,如果开发人员在构造函数中编写一些代码,会发生什么?
在这种情况下,会出现一个特殊的新对象状态由于对象已构造,但尚未调用init函数,因此是“半初始化”状态我们应该修改对象(特别是析构函数)来处理这个新状态这意味着,给每个方法添加新条件有人可能想说,这还不是因为你人为地添加了不使用异常的限制?!如果构造函数中抛出异常,C++运行时会正确地清理对象,不会出现“半初始化”状态。
话虽如此,然而问题在于,如果使用异常,如上所述,就必须处理所有与异常相关的复杂性对于一个需要在遇到故障时表现出优秀的健壮性的基础设施组件来说,这不是一个合理的选择此外,即使初始化没有问题,对象的销毁也绝对会遇到问题。
你不能在析构函数中抛出异常这可不是我强加的人为限制,而是因为如果在进程中调用析构函数,或者恢复栈时恰好抛出异常,就会导致整个进程崩溃因此,如果销毁可能失败,你就需要两个单独的函数来处理它:class foo{public:…int term ();~foo ();};
这就遇到了与初始化相同的问题:一个“半终止”状态,我们必须以某种方式处理,向各个成员函数添加新条件class foo{public:foo () : state (semi_initialised){…}int init (){if (state != semi_initialised)handle_state_error ();…state = intitialised;}int term (){if (state != initialised)handle_state_error ();…state = semi_terminated;}~foo (){if (state != semi_terminated)handle_state_error ();…}int bar (){if (state != initialised)handle_state_error ();…}};。
与之相比,C语言的代码如下其中只有两种状态未初始化对象/内存,我们无需担心上述问题,而且结构可以包含任意数据而且只要对象进入已初始化的状态,就可以正常工作因此,对象中不需要状态机:struct foo{…};int foo_init (){…}int foo_term (){…}int foo_bar (){…}。
考虑一下,如果在上述代码中添加继承,会发生什么C++允许将基类初始化为派生类构造函数的一部分如果抛出异常,就会破坏已成功初始化的对象:class foo : public bar{public:foo () : bar () {}…};。
然而,一旦引入单独的init函数,状态的数量就会开始增长除了未初始化、半初始化、初始化和半终止状态之外,你还会遇到这些状态的组合你可以想象一个基类已完全初始化、但派生类半初始化的对象对于这样的对象,几乎不可能确保其行为不出问题。
对象的半初始化和半终止部分有很多不同的组合,并且鉴于它们只在非常罕见的情况下才会引发故障,因此大多数相关代码可能未经测试就进入了生产综上所述,我认为,如果你的需求是不允许出现未定义的行为,则不适合面向对象的编程。
这个问题不仅限于C++,任何具有构造函数和析构函数的面向对象语言都不适合因此,更适合面向对象语言的项目是:对开发速度有要求、但对“不存在未定义的行为”没有太高要求这个问题没有灵丹妙药系统编程选择C语言更为合适。
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需!
7. 如遇到加密压缩包,请使用WINRAR解压,如遇到无法解压的请联系管理员!
8. 精力有限,不少源码未能详细测试(解密),不能分辨部分源码是病毒还是误报,所以没有进行任何修改,大家使用前请进行甄别
丞旭猿论坛
暂无评论内容