打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
为什么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, whendiscussing 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 theonly reason people use C++, then why don’t they just use C? C isadmittedly more efficient than C++ (yeah, yeah, I know it has beenproved 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

Iknow you are going to say “better abstraction mechanism”, because afterall C++ is designed to be a better C, one that has uncompromisedefficiency and yet at the same time has all those fancy high-levelfeatures. But then the problem comes down to “does it really matter if the developers need those fancy features?  Imean, 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 moreKISS 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.

 

Thereal serious impact of this phenomenon is that it drives more people toC when they’re weighing their options, be them C and C++; and once theystart using C, they will soon get satisfied and comfortable with whatsuffices, 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 Cis a better choice than C++. For instance, device driver development isusually something that doesn’t need fancy OOP/GP techniques. It’s justsimple data manipulation; what really matters is the programmers knowexactly how the system works, and what they’re doing. Now what about OSdevelopment? I’m not a guy who’s been involved in any kind of OSdevelopment myself, but having read a fair amount of OS code (Unixmostly), I’ve come to feel that there’s a significant part of the OSdevelopment 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.

 

Firstof all, when people are concerned about efficiency, there’re really twokinds of efficiency – time efficiency (e.g. OS, runtime, real-timeapplications, high-demanding systems) and space efficiency (e.g. allsorts of embedded systems). However, this categorization doesn’t reallyhelp us determine whether we should use C or C++, because C and C++ areboth 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 “enterpriseapplication business”). For example, is it better to use OOP/GP toexpress the logic or is it better off being kept pretty much just aboutdata and procedures.

 

Fromthis point of view, we can vaguely divide applications into twocategories (of course, with the premise that what we’re concerned withis C/C++, not java/c#/ruby/erlang etc.): low-level applications andhigh-level applications, where low-level applications means the oneswhere fancy abstractions such as OB/OOP and GP are pretty much of nouse, and high-level means all the rest. Now, obviously, of all theareas 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, evenin those areas where programmers don’t use high-level abstractions intheir 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 touse 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.). Andfinally, 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);

 

Ithink this is exactly the reason why one should use C++ even in thosecases 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 anefficient container (or a smart pointer) will save you from all theboring job of manual manipulation of memory, then what’s the point ofusing the primitive malloc/free? If a better string class (I’m nottalking about std::string; everybody knows it’s not the best C++ cando) or regex class  can relieve you of all thecluttered string-manipulation code you don’t even want to look at, thenwhat’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 (andI know, of course, C++ need lambda function support for those – that’swhat C++0x is for), then what’s the point of hand-written for-loops? Ifhigh-order function is really what you need, then what’s the point ofusing awkward workarounds to approach the same deal?

 

KISSdoesn’t mean “primitive”; KISS means using the most suitable tool foryour job, where “most suitable” means the tool you use should help youexpress 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

Peoplemight say that C++ is much more easily misused than properly-used, andC, on the other hand, is always more manageable and controllable as tocomplexity. In C++, an average programmer might come up with a wholebunch of highly coupled classes that degenerates fast into a big mess.But this is actually a separate issue. On the one hand, it can prettymuch occur in any object oriented language. There’realways programmers who dare to write classes on top of classes evenbefore they have any idea what HAS-A is and what IS-A is; theylearn all the syntax of defining a class and inheriting one fromanother and they thought they’ve grasped the essence of OOP. On theother hand, the reason it appears to be more seriousin C++ is because C++ has so many accidental complexities that impedethe design, and because C++ is so flexible that pretty much everyproblem in C++ has several alternative solutions (thinking of all theGUI libraries) so that weighing all the options becomes a hard jobitself. The accidental complexities are a historical baggagethat C++0x is trying so hard to (and hopefully will) get rid of; theflexibility with respect to design isn’t actually a bad thing if youthink about it - it helps good designers make good designs; and ifsomeone 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. Andif you’re so worried that your fellow C++ coders will be enticed byfancy high-level features and that your project will eventually getscrewed, 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), notflinching away just because there’re risks (risks that can be avoidedby 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 willfind it and people will be attracted by it, and it will draw energyfrom the main people effort of doing something really useful (It’s kindof like the Murphy's Law), let alone the ones that can lead to an (onsome level) elegant solution to a real problem. Peopleare inherently attracted by scarce resources. Corollary: Tricks andbizarrenesses 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 (onsome level) elegant solutions to real problems. Think about it thisway: if you’re put in a place where either you have to use tricks toimplement something really useful or you don’t implement it so otherpeople won’t have the benefit of using it. What would you choose? Iknow 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.

 

AsBjarne Stroustrup said, obviously C++ is too complicated; obviouslypeople get scared and sometimes turn away. But “people need relativelycomplex language to deal with absolutely complex problems”. We can’tmake a language more powerful by taking features away from it. Complexfeatures like templates and even multiple-inheritance can be useful ifthey’re exactly what you need, you just have to use them very carefullyand 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 thelanguage supports (there’re only three). And that’s a very importantreason 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’sabsolutely huge amount of them out there; check all the C++ books andmaybe 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 useit, 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

 

Dowe need abstractions in our code (think very carefully on this one,because it’s very hard to estimate whether the benefit of using thehigh-level features of C++ outweighs the risk of using themincorrectly; the proper answer depends on how well trained yourprogrammers are, what coding standard you follow and how well it’senforced, etc.)?

If so, then use C++. Otherwise,

 

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

Ifso, then use C++, but meanwhile always remember what you are doing – ifyour code doesn’t really need all the fancy abstractions, then try notto 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, butbe very careful. On the other hand, if you need neither abstractionmechanisms in your code nor quality C++ libraries because what you’redoing is so simple that you don’t even need convenient components likecontainers or strings, or you decide that the benefit C++ can bring youin your project is minor to an extent that it’s not even worth takingthe 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).

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
软件架构设计的六大原则
设计原则-SOLID
The best of C++ is what’s coming – CppDepend Blog
考研英语作文范文155篇:(145)老师讲授还是讨论式课堂?
JavaScript editing
3 Useful Gedit Plugins For Programmers | MyLinuxBook
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服