`

为什么C++

 
阅读更多

Why C++

刘未鹏(pongba)

C++的罗浮宫(http://blog.csdn.net/pongba)

非常感谢waterwalk翻译了整篇文章,我整理了之后单独贴了出来,见这里

The Problem

So, why C++? Before you frown and turn away. Just try to answer this simple question.

Efficiency, right? Everybody knows the answer. But as it turned out, when discussing a programming language or everything related to one, one should be very specific. Now why’s that? Let me ask you another question: if efficiency is the only reason people use C++, then why don’t they just use C? C is admittedly more efficient than C++ (yeah, yeah, I know it has been proved that C isn’t to any significant extent more efficient than C++, so don’t get me wrong here, because even if they are equally efficient, the problem still exists).

The Myth

I know you are going to say “better abstraction mechanism”, because after all C++ is designed to be a better C, one that has uncompromised efficiency and yet at the same time has all those fancy high-level features. But then the problem comes down to “does it really matter if the developers need those fancy features? I mean, after all we all have been hearing voices about KISS and stuff, and we all have heard about the claim that, compared to C++, C is more KISS so we should use C. This unstoppable argument has turned the comparison between C and C++ into a big myth (or maybe a mess). And surprisingly, it seems that many people do incline to C, the reason mostly being that C++ is so hard to use right. Even Linus thinks so, too.

The real serious impact of this phenomenon is that it drives more people to C when they’re weighing their options, be them C and C++; and once they start using C, they will soon get satisfied and comfortable with what suffices, experiencing what is called “satisfaction”. This is when they will come out and claim that C actually is a better choice than C++ even though they didn’t actually try to use C++ or they aren’t adequately good C++ programmers at all. The real answer, however, almost always begins with “it depends”.

So, did I say “it depends”? On what? Obviously there’re some areas where C is a better choice than C++. For instance, device driver development is usually something that doesn’t need fancy OOP/GP techniques. It’s just simple data manipulation; what really matters is the programmers know exactly how the system works, and what they’re doing. Now what about OS development? I’m not a guy who’s been involved in any kind of OS development myself, but having read a fair amount of OS code (Unix mostly), I’ve come to feel that there’s a significant part of the OS development that doesn’t need OOP/GP either.

However, does that mean that, in all those areas where efficiency matters, C is a better choice than C++? Not really.

The Answer

Let’s do this case by case.

First of all, when people are concerned about efficiency, there’re really two kinds of efficiency – time efficiency (e.g. OS, runtime, real-time applications, high-demanding systems) and space efficiency (e.g. all sorts of embedded systems). However, this categorization doesn’t really help us determine whether we should use C or C++, because C and C++ are both extremely efficient as to both time and space. What really affects our language choice (between C and C++, of course) is the business logic (here by “business”, I don’t mean the “enterprise application business”). For example, is it better to use OOP/GP to express the logic or is it better off being kept pretty much just about data and procedures.

From this point of view, we can vaguely divide applications into two categories (of course, with the premise that what we’re concerned with is C/C++, not java/c#/ruby/erlang etc.): low-level applications and high-level applications, where low-level applications means the ones where fancy abstractions such as OB/OOP and GP are pretty much of no use, and high-level means all the rest. Now, obviously, of all the areas where C/C++ is used (because of their high-efficiency), there’re a significant number of “high-level” applications (see those listed on Bjarne Stroustrup’s homepage), where abstraction is just as important as, if not more important than efficiency. And those are precisely the places where C++ is used and useful in a unique sense, and where C++ is a better choice than C.

Wait, there’s more. As it turns out, even in those areas where programmers don’t use high-level abstractions in their code per se, there might be a reason they should use C++, too. Why’s that? Just because your code don’t use class or templates doesn’t mean it doesn’t use a library that does. Considering the availability of all the handy C++ library facilities (with tr1/tr2 coming soon), I think there’s a pretty strong reason to use C++ in these cases - you can stick to the C core of C++ when coding (KISS in any way you want), and at the same time you’ve got some awesome C++ libraries at your disposal (e.g. STL containers and algorithms, tr1/tr2 components, etc.). And finally, there’s this one thing that’s always ignored by many people – sometimes KISS relies on abstractions. I think Matthew Wilson made a crystal clear point about this in the prologue of his new book “Extended STL, Vol 1”, where he laid down two blocks of code, one written in C and one in C++:

// in C

DIR* dir = opendir(".");

if(NULL != dir)

{

struct dirent* de;

for(; NULL != (de = readdir(dir)); )

{

struct stat st;

if( 0 == stat(de->d_name, &st) &&

S_IFREG == (st.st_mode & S_IFMT))

{

remove(de->d_name);

}

}

closedir(dir);

}

// in C++

readdir_sequence entries(".", readdir_sequence::files);

std::for_each(entries.begin(), entries.end(), ::remove);

And it’s even simpler in C++09:

// in C++09

std::for_each(readdir_sequence(".", readdir_sequence::files), ::remove);

I think this is exactly the reason why one should use C++ even in those cases where he doesn’t really need class or templates in his own code – the handy C++ libraries he will find very useful does. Similarly, if an efficient container (or a smart pointer) will save you from all the boring job of manual manipulation of memory, then what’s the point of using the primitive malloc/free? If a better string class (I’m not talking about std::string; everybody knows it’s not the best C++ can do) or regex class can relieve you of all the cluttered string-manipulation code you don’t even want to look at, then what’s the point of doing it manually. If a ‘transform’ (or a ‘for_each’) can do your job in one line so succinctly and clearly (and I know, of course, C++ need lambda function support for those – that’s what C++0x is for), then what’s the point of hand-written for-loops? If high-order function is really what you need, then what’s the point of using awkward workarounds to approach the same deal?

KISS doesn’t mean “primitive”; KISS means using the most suitable tool for your job, where “most suitable” means the tool you use should help you express your mind as straight (and succinct) as possible, as long as it doesn’t compromise the readability and understandability of the code.

The Real Problem

People might say that C++ is much more easily misused than properly-used, and C, on the other hand, is always more manageable and controllable as to complexity. In C++, an average programmer might come up with a whole bunch of highly coupled classes that degenerates fast into a big mess. But this is actually a separate issue. On the one hand, it can pretty much occur in any object oriented language. There’re always programmers who dare to write classes on top of classes even before they have any idea what HAS-A is and what IS-A is; they learn all the syntax of defining a class and inheriting one from another and they thought they’ve grasped the essence of OOP. On the other hand, the reason it appears to be more serious in C++ is because C++ has so many accidental complexities that impede the design, and because C++ is so flexible that pretty much every problem in C++ has several alternative solutions (thinking of all the GUI libraries) so that weighing all the options becomes a hard job itself. The accidental complexities are a historical baggage that C++0x is trying so hard to (and hopefully will) get rid of; the flexibility with respect to design isn’t actually a bad thing if you think about it - it helps good designers make good designs; and if someone blame them for hurting his brain then maybe it’s his problem, not the language’s; maybe he shouldn’t be the one to make a design. And if you’re so worried that your fellow C++ coders will be enticed by fancy high-level features and that your project will eventually get screwed, then maybe what you should do is setting up a coding standard and enforce it (or you can just follow the collective wisdom, or stick to the C core or C with class part of C++ if necessary), not flinching away just because there’re risks (risks that can be avoided by policies), because then you will not be able to access all the C++ libraries anymore, mind you.

On the other hand, there’s this more important psychological problem – if there’s a bizarreness in a language, then eventually someone will find it and people will be attracted by it, and it will draw energy from the main people effort of doing something really useful (It’s kind of like the Murphy's Law), let alone the ones that can lead to an (on some level) elegant solution to a real problem. People are inherently attracted by scarce resources. Corollary: Tricks and bizarrenesses are scarce resources, so they draw people’s attention, not to mention the fact that mastering a trick makes one feel special in the herd. The bottom line is, even useless tricks draw people’s attention so heavily.

How many black corners are there in C++? How many tricks are there in C++? All in all, how many accidental complexities are there in C++?

To be fair, most of the tricks and (you might say) techniques that have been discovered in recent years (i.e. modern C++) are driven by real needs, particularly the needs to implement highly flexible and generic library components (thinking of all the components in boost). And they did lead to (on some level) elegant solutions to real problems. Think about it this way: if you’re put in a place where either you have to use tricks to implement something really useful or you don’t implement it so other people won’t have the benefit of using it. What would you choose? I know that the boost heroes chose the former – implementing them, no matter how hard and tricky and cumbersome the implementation is.

But all those arguments don’t change the fact that we deserve to have a language that supports a clean way to express our minds in code. Take boost.function/boost.bind/boost.tuple for examples, variadic templates will tremendously simplify (by reducing the LOC to nearly 1/10 of the original) the implementation of the three (and many, many more to come) libraries, and the code will become succinct and as simple as possible, too. Auto, initializer-list, rvalue-reference, template-aliasing, strong-typed enums, delegating-constructors, constexpr, alignments, inheriting-constructors, etc; all those C++0x features, they all have one goal – eliminating the various accidental complexities or embarrassments of the language.

As Bjarne Stroustrup said, obviously C++ is too complicated; obviously people get scared and sometimes turn away. But “people need relatively complex language to deal with absolutely complex problems”. We can’t make a language more powerful by taking features away from it. Complex features like templates and even multiple-inheritance can be useful if they’re exactly what you need, you just have to use them very carefully and by necessity so that you don’t shoot yourself in the foot. Of all the complexities in C++, the ones that really get in our way are the accidental complexities (someone might call them “embarrassments”), not the paradigms the language supports (there’re only three). And that’s a very important reason why we should embrace C++0x, because it aims at eliminating the long standing accidental complexities C++ had and make obsolete all the arcane tricks (there’s absolutely huge amount of them out there; check all the C++ books and maybe the boost library and you’ll know what I’m talking about) so that we can express our mind clearly and directly.

The Conclusion

C++ is hard, and even harder to use correctly. So when you decide to use it, be careful, always know where you are and what you really want. Here’s a simple guideline:

Do we need to be efficient?

If so, then

Do we need abstractions in our code (think very carefully on this one, because it’s very hard to estimate whether the benefit of using the high-level features of C++ outweighs the risk of using them incorrectly; the proper answer depends on how well trained your programmers are, what coding standard you follow and how well it’s enforced, etc.)?

If so, then use C++. Otherwise,

Do we need good C++ libraries to ease our job?

If so, then use C++, but meanwhile always remember what you are doing – if your code doesn’t really need all the fancy abstractions, then try not to get sucked into them; don’t use class or templates just because you’re writing code in a .cpp file and using a C++ compiler.

Otherwise, use C, but then you might wonder why not just use the C core of C++. The same reason as always: people get easily sucked into fancy language features even when they don’t really know if they’re going to helpI can’t tell you how many times I wrote a bunch of classes only to find out “what the heck are these classes for?”. So, if you can stick to the C core or C with class part of C++ and keep simple things simple, or if your code needs a migration path from C to C++, use C++ then, but be very careful. On the other hand, if you need neither abstraction mechanisms in your code nor quality C++ libraries because what you’re doing is so simple that you don’t even need convenient components like containers or strings, or you decide that the benefit C++ can bring you in your project is minor to an extent that it’s not even worth taking the risk, or you just simple don’t have enough people that can use C++ in a proper way, then maybe you should stick to C.

The bottom line: keep simple things simple (but remember that simplicity can be achieved by using high-level libraries); use abstractions when necessary (and even then, make spare use of it; follow good design principles and established good practices).

--

我的讨论组

TopLanguage

分享到:
评论

相关推荐

    为什么C++对自动驾驶如此重要?.pdf

    为什么C++对自动驾驶如此重要, 自动驾驶C++学习路线

    C++中回调函数(CallBack)的用法分析

    这也可以理解为什么C++类的多个实例可以共享成员函数却-有不同的数据成员。由于this指针的作用,使得将一个CALL-BACK型的成员函数作为回调函数安装时就会因为隐含的this指针使得函数参数个数不匹配,从而导致回调...

    C++语言精华 详细

    既然如此,为什么c++又定义另外一个系 统?答案是C的I/O系统一点也不了解对象。所以,为了使c++完全支持面向对象的程序 设计,有必要建立一个能对用户定义的对象进行操作的面向对象的I/O系统。除了支持对象 ...

    《C++编程艺术》教程+代码

    3.2 为什么C++没有内建支持多线程 55 3.3 选用什么样的操作系统和编译器 56 3.4 Windows线程函数概述 56 3.4.1 线程的创建和终止 56 3.4.2 Visual C++对CreateThread()和ExitThread()的替换 57 3.4.3 线程的挂起和...

    C++ 无法执行程序错误

    NULL 博文链接:https://lingbjxm.iteye.com/blog/1177995

    C++编程思想.pdf

    1.2 为什么C++会成功 3 1.2.1 较好的C 3 1.2.2 采用渐进的学习方式 4 1.2.3 运行效率 4 1.2.4 系统更容易表达和理解 4 1.2.5 “库”使你事半功倍 4 1.2.6 错误处理 5 1.2.7 大程序设计 5 1.3 方法学介绍 5 1.3.1 ...

    C++常见问答

    为什么 C++ 允许不安全的代码? 学习 C++: 为了成为真正的 OO 程序员,在学 C++ 之前,我需要先学一门纯 OO 语言吗? 标准化: 为何 C++ 没有图形用户接口? 为何 C++ 不支持线程? C++0x 会是什么样的? 书籍: ...

    C++实现txt文件的读写

    详细介绍了如何使用C++对txt文件进行读写,并有示例代码。

    我们为什么可以不学C++

    我们为什么可以不学C++,介绍 C++,C#以及Java的学习过程是否需要 C++ 的知识

    Effective Modern C++:改善C++11和C++14的42个具体做法(中文版 + 英文版)

    作者简介 作者:(美国)迈耶斯(Scott Meyers) 迈耶斯(Scott Meyers),二十多年来,Scott Meyers的Effective C++系列书籍(包括《Effective C++》《More Effective C++》和《Effective STL》)为C++编程语言...

    C++为什么需要重载函数

    C++为什么要重载函数,以及如何实现重载函数机制。

    c++精粹c++精粹c++精粹c++精粹

    他曾为多家机构提供技术咨询服务,包括DEC公司、苹果公司、斯坦福线性加速器研究中心、Xylinx和Gupta公司等。 本书介绍了C++的程序结构、词法符号、常量、声明及作用域规则、文件链接规则、类型、类型转换、表达式...

    C++ Lambda Story - From C++98 to C++20.pdf

    添加了有关如何操作的新部分从 C++14 章节中不推荐使⽤的 bind1stin 转换为现代替代⽅案。 C++11 和 C++17 章节中改进和扩展的 IFFE 部分 带有 lambda 技术列表的新附录 带有五⼤ lambda 功能列表的新附录,改编⾃...

    C++入门到精通(深入C++系列)

    在所有的编程语言中C++可以说是最为复杂的它既是一门传统的编程语言也是...为C++用户提供了最为基本的基础设施C++经历了多年的发展终于有了一个相对稳定的版本所以我们应该用一种新的眼光来看待C++ 而不再简单地把C++...

    《C++17 完全指南》

    本书为《C++17 the complete guide》(第一版) by Nicolai M. Josuttis的个人中文翻译版, 仅供学习和交流使用 C++17是现代 C++编程中的下一个版本,最新版本的gcc、clang和 Visual C++ 都至少已经部分支持它。尽管 ...

    小熊猫c++开发工具(Dev-C++升级版本)免安装版本

    因为教学的需要,作者从2012年开始接触和使用这个编辑器,并在其停止更新后决定在其基础上继续更新,并命名为小熊猫Dev-C++。 目前已经修改和完善的功能亮点包括: 优化改进代码补全提示功能: 随输入自动显示补全...

    高速上手C++11/14/17

    C++ 是一个用户群体相当大的语言。从 C++98 的出现到 C++11 的正式...之为传统 C++)而未接触过 C++11/14/17 的 C++ 程序员在见到诸如 Lambda 表达式这类全新特性 时,甚至会流露出『学的不是同一门语言』的惊叹之情。

    Visual C++源代码 30 如何为应用程序添加背景音乐

    Visual C++源代码 30 如何为应用程序添加背景音乐Visual C++源代码 30 如何为应用程序添加背景音乐Visual C++源代码 30 如何为应用程序添加背景音乐Visual C++源代码 30 如何为应用程序添加背景音乐Visual C++源代码...

    为什么做游戏开发要学C++.

    为什么做游戏开发要学C++

    用C++编写的可识别一个数是不是科学记数法表示

    用C++编写的可识别一个数是不是科学记数法表示,亦可识别实数

Global site tag (gtag.js) - Google Analytics