编程与软件工程250bpm.com
为什么我该用 C 而不是 C++ 写 ZeroMQ
Why should I have written ZeroMQ in C, not C++
2012 — 2022,它一次次回到首页
黑点是上首页(≥ 50 分)的那次投稿,空心点是没冲上去的投稿,点越大分数越高。
导读
ZeroMQ 作者 Martin Sustrik 回顾当年为何用 C 而非 C++ 重写该项目:C++ 的异常机制导致错误处理路径复杂、对象可能处于半初始化状态,而 C 强制显式处理每一步,代码更可控。文章引发了关于异常、构造函数与语言选择的长期争论。
为什么经久不衰:它以一个真实大型项目的亲身经历,把“C++ 异常与构造函数的坑”讲得具体透彻,至今仍是语言设计与错误处理讨论的经典参照。
HN 评论精选
问题在于用法而非异常特性本身,深入理解 C++ 就能用好它
这说法很荒谬。异常不过是泛化了的返回值,用得好就有收益,用得差就是噩梦——任何语言的任何特性都如此。你可以选择不用异常,但不能怪罪这个特性本身。我用了半辈子 C++,它确实千疮百孔,但花时间深入理解后照样能干活。别因为语言不适合你的问题或思维方式就抱怨它。
evincarofautumn查看英文原文
This is absurd. Exceptions are just generalised returns. You can use them well and benefit from them, or use them poorly and make the stuff of nightmares. It’s the same with any feature of any language. You can choose not to use exceptions in your code, if that makes it easier for you to understand and manage, but it’s certainly not the fault of the feature in general. Basically, it’s up to you to structure your code well. Yes, it gets bad if a potentially throwing function can be called from multiple points. The error needs to be handled at every one of those points, and probably in much the same way. But if you see repetition, why aren’t you factoring it? And why are you calling that function from multiple unrelated locations in the first place? I get it. I’ve used C++ for half a lifetime—it’s a hopelessly broken language. There are tons of things about it that just make me furious. But I can get stuff done in it because I’ve taken the time to understand it in depth. Don’t complain about the language or a particular feature thereof just because it’s not suited to your problem or your way of thinking. There are other languages out there (Erlang) that are far better suited to stable zero-downtime systems than C++. There are languages (Haskell, Lisp) that help you better manage complexity than C++. Every language implementation worth its salt has C bindings, so you can write performance-critical code at a low level, while still managing the whole system in a high-level language. There are options. Explore them!
这是设计问题而非语言问题,可以不用异常写 C++
这看起来主要是对异常的抱怨,但 C++ 并不强制你用异常,内存分配也可以用不抛异常的方式。我们出于文中所述原因不用异常,改用 boost::system::error_code。至于半初始化状态的问题,作者似乎是在不用异常的情况下硬做 OOP,更通用的编程方式或许能解决。这更像设计问题而非语言问题。
shin_lao查看英文原文
It looks mainly looks like a rant on exception, but nothing forces you to use exceptions with C++. You can even allocate memory in a way that doesn't throw. We don't use exceptions for the reasons described in the article (and many others), we use boost::system::error_code instead. But that's for the first half of the article, and the OP admits that he simply gave up on exceptions. As for the part about half-initialized state, I think the problem is that the author is trying to do OOP in C++ without exceptions. Perhaps a more generic programming approach would solve his "half initialized problem". Don't want to sound like a snob, but it really looks more like a design problem than a language problem.
C++ 是 C 的超集,不必全盘抛弃,或考虑更合适的语言
这有点因噎废食。批评虽有道理,但 C++ 实际上是 C 的超集,如果 C 的惯用法更好用,直接用就是了。我在写内核代码时不得不用纯 C,真的很怀念 C++ 额外的类型安全。不过对作者的场景,Erlang 或 Ada 这类面向高可用性的语言也许是更好的选择。
pmjordan查看英文原文
This strikes me as throwing the baby out with the bathwater. While the criticisms are valid, and people love to hate C++ for all sorts of reasons (I avoid C++ exceptions altogether), C++ is for practical purposes a superset of C, so if a C idiom works better than its C++ equivalent, you can just use it instead. I've been working on a project which has necessarily been written mostly in pure C (kernel code), and I do really miss C++'s extra type safety. (GCC has some type warnings that help, but it's still not as safe) Then again, maybe an entirely different language, geared towards high availability, such as Erlang or Ada, might have been a better choice in the author's case.
高可靠性系统用 C++ 需要更多纪律,嵌入式场景应避免异常
这很好地解释了为什么我强烈反对在嵌入式代码中使用异常。构造函数也有替代方案:让对象内含错误码,或用空构造函数加 init 方法的模式包装成静态方法作为真正的构造函数。但这再次说明高可靠性系统在 C++ 中需要远比在 C 中更多的纪律——C++ 给你的绳子更长,更容易吊死自己。
aidenn0查看英文原文
This describes quite well why I strongly recommend against exceptions in embedded code. There are ways that you can use constructors, one way is to have an error-code as part of the object that the constructor can set. Another way is to use the empty-constructor/init-method pattern that he talks about and wrap it in a static method (or function) and that becomes your actual constructor. I think you can even make the constructor private which will prevent accidental calling of it. But this is just another example of why high-reliability systems require considerably more discipline in C++ than in C, since C++ gives you more rope, it's easier to hang yourself. There is an argument that such a limited dialect of C++ is so close to C (with a good 3rd party data-structures library) that there is no point to C++ in such situations (which seems to be the point the article is making), and I tend to go back and forth on this.
库选 C 以保证可移植性,独立应用选现代 C++
我们公司达成的共识是:如果要写嵌入到宿主应用中的软件库,就毫不犹豫选 ANSI C 或 C99——绑定容易写,且 C 的可移植性让代码几乎能跑在所有平台上。反之,如果要写独立软件如桌面应用、网络服务器、游戏等,现代 C++ 应是首选——智能指针、内置线程、lambda 用起来很愉快。
symisc_devel查看英文原文
The consensus we have reached at our company is as follows: 1. If you plan to write a software library [0] to be embedded directly onto foreign piece of code (i.e a host application), then go blindly with ANSI C or C99 at last resort. Not only writing bindings for your code should be straightforward but you will also benefit from the portability of C that make your code virtually available on every platform or architecture out there. Remember write once, run everywhere. Well, C fits exactly onto this category. 2. If on the other side you plan to write a standalone software such as a Desktop app, a network server, a game, etc. then modern C++ should be your first choice. You'll largely benefit from shared/unique pointers, built-in threading, lambdas, high performance data structures with relative portability accros modern systems. C++11/14/17 is a joy to program with once you master the basics. [0]: https://sod.pixlab.io Edit: formatting.
作者没掌握健壮 C++ 的写法,不能归咎于语言
作者到 2012 年(五年之后)还没学会在不无谓地把自己限制成 C 的情况下写出健壮的 C++,这不是偏好 C 的充分理由。“医生,我这样做会疼”——那就别那样做。学会什么行得通什么行不通,别因噎废食。
jdashg查看英文原文
That the author didn't understand how to write robust C++ by 2012 (after 5 years) without constraining themselves unnecessarily to C is not a compelling reason to prefer C over C++. "Doctor it hurts when I do this." Well stop doing that then. Learn what works and what doesn't, but don't throw the baby out with the bathwater.
严格处理错误的 C 代码同样复杂,两种语言都只能靠“良好子集”生存
文章主要针对异常,这还算公道。但当你写处理所有错误的 C 代码时,最终会看到 goto fail、手工析构、宏包装的 goto 等,代码并不比示例好看。到这个地步不如直接用 C++。另外考虑构造函数抛异常的数组场景:100 个对象中第 42 个构造失败,你怎么知道哪些已初始化?C 和 C++ 最终都定义了一个你应该待在里面的“良好子集”,这很说明问题。
fefe23查看英文原文
The article is mostly about exceptions, which is fair I guess. However, by the time you write C code that handles _all_ errors (like exception handling would), you end up with code that does not look as nice as the examples given here. In production C code you often end up seeing a "goto fail" or "goto done" and then hand-written destruction of objects. To make that less error prone, you have to explicitly initialize everything in the beginning of the function. Oftentimes you even see the "goto fail" invoked via a macro. Now, in my humble opinion, by this time you might as well have used C++. Persponally, I do like the regularity of such code when reading other people's code. Still. It's a lot of effort. And the benefits over exception handling are not so obvious to me. You end up restricting yourself in both cases. Also, when considering whether constructors and destructors should throw exceptions, consider the array case. You instantiate an array of 100 foo. If constructor #42 throws, how do you know which ones have been initialized and which ones haven't? Even worse, if you delete[] an array and one of the destructors fails -- do you get memory leaks? Maybe the destructor was supposed to release a mutex and you can get deadlocks? I find it very telling that both C and C++ (and most other languages for that matter) end up defining a "good subset" that you are supposed to stay inside. You would be forgiven for concluding that we don't know what we are talking about when we design new languages, and we should not hastily add new features lest we end up having to recommend against them in the future. Yet, many languages (I'm looking at C# and Javascript here) keep getting new features on a yearly basis. I think we should be much more sceptical. I also think this is a dilemma that is similar to the startup dilemma. It is a very risky proposition, so the people who end up doing it are not risk averse and tend towards the "hold my beer" part of the spectrum.
历次讨论
同类还值得读
开源应用架构
The Architecture of Open Source Applications
《开源软件架构》(AOSA)是一本在线免费书,邀请知名开源项目的作者亲自剖析其内部设计,涵盖 SQLAlchemy、LLVM、Audacity、Apache、Bash 等系统。
编程与软件工程上首页 9 次 · 2011–2024aosabook.org编辑精选编程语言简史:简短、不完整且多半错误
A Brief, Incomplete, and Mostly Wrong History of Programming Languages
一篇以戏谑、故意不准确的方式回顾编程语言史的博客文章,用夸张轶事和讽刺定义串起 Lisp、C、C++、Java、JavaScript、PHP 等语言。
编程与软件工程上首页 8 次 · 2009–2021james-iry.blogspot.comSQLite 是如何测试的
How SQLite is tested
SQLite 官方文档页,系统介绍 SQLite 的测试体系:多种测试方法(TCL 测试、模糊测试、回归测试、静态分析等)和海量测试用例,展示了这个小型开源项目如何靠极致测试获得…
编程与软件工程上首页 8 次 · 2009–2025sqlite.org编辑精选高级编程语言(2009)
Advanced programming languages (2009)
Matt Might 的经典文章,按用途推荐“高级编程语言”:如果追求就业就选主流语言,如果追求表达力、学术研究或创业,则推荐 Haskell、OCaml、Scala 等函数式语…
编程与软件工程上首页 8 次 · 2009–2022matt.might.net我的 Forth 与栈机器经历
Yosefk - My history with Forth & stack machines
作者以亲身经历回顾了使用 Forth 语言和栈式机器的历程:既赞叹其简洁优雅、代码量小、可自举的优点,也坦率指出栈操作在实际编程中的痛苦,以及 Forth 社区文化中的问题。
编程与软件工程上首页 8 次 · 2010–2024yosefk.com编辑精选