| 查看: 1753 | 回复: 5 | |||
cfem_nli新虫 (初入文坛)
|
[交流]
【分享】在大的项目中为什么不用c++[也顺便测试一下你的c++基本水平]已有4人参与
|
|
语言之争历来有之,可谓是经久不息. 大一统的原则在这里并不适用. 对于科学计算, 很多人一直在为c++做宣传,为其翻身. 可是c++本身的缺点也是显而易见的,太过于复杂,一个优秀的c++程序员实在是不好找. 转载一篇很久以前看到的文章, 从电脑里翻出来,忘了出处了, 哪位要是知道麻烦广而告之. 看着篇文章,也顺便测试一下你的c++基本水平. 这是英文原文,后面附带了链接,可以下载.没有时间做适当的翻译,如果哪位仁兄实在有此需要的话,我再尽量找时间补上;要是有人能够翻译了,在这里先行谢过了. Why I Dislike C++ For Large Projects By Mark Roulo My primary complaint against C++ is that the language is so complicated, and has enough booby-traps, that average and above-average programmers have a difficult time writing code without serious bugs. In a large program with raw pointers, the quality of the program will largely be driven by the least talented members of the team. This makes it highly dangerous to select a language that requires all the programmers to be in, say, the top 25% of the talent pool. Given a team with 10 developers (and my projects typically have more like 40-50), this seems to be asking for lots of long term trouble. Things become even more unstable when one considers that the average turnover of software developers in Silicon Valley (where I live and work) is something like 20-25% and that many large projects also use contractors. The total number of programmers on a project will be much higher than the average (or even the peak) number of developers on the project. I have worked on a project with both C++ and Java components (roughly 50% each) that communicate via CORBA. Part of my job has been to interview candidates for both halves of the project over a period of several years. This has given me a fair amount of exposure to the C++ developer pool. As part of my standard interview for C++ candidates I ask them to write me a small class with the intention of evaluating their command of the language. This also gives us a reasonable coding sample to discuss during the interview. I can ask about potential improvements, extensions and testing strategies. Most of the candidates I interview have already made it to the top of the resume pool -- usually by claiming at least 3 years professional experience with C++. Since many resumes have this, the candidates tend to have some other plus: large systems experience, degree from a good school, personal recommendation, etc. The candidates then must survive a phone screen interview whose job is to weed out candidates that can't, for example, describe any of their projects coherently. My request is to: Write a Named Point class with three members: two floating point values for the coordinates on an X-Y plane, and a name represented as a 'char *'. Assume that this class will be used for some sort of wargame or simulation program that treats the world as flat and that these named points will be used to represent things like cities, battlefields, etc. A typical first try looks something like this: class NamedPoint { private: float x; float y; char *name; public: NamedPoint (float x, float y, char *name) { this->x = x; this->y = y; this->name = name; } float getX() {return x;} float getY() {return y;} char *getName() {return name;} void setX(float x) {this->x = x;} void setY(float y) {this->y = y;} void setName(char *name) {this->name = name;} }; There are several problems with this code: • name has its encapsulation violated with the getName() method. • The code calling the constructor is responsible for managing the scope of the member variable 'name'. This code fragment shows the problem: • // Ignore for now a lot of awfulness in this function ... • // this should probably be a constructor in a sub-class • // of NamedPoint, 'cityName' and 'countryName' should be • // checked for NULL _and_ for length so that sprintf() • // doesn't overrun temp ... • // • // The point is that if NamedPoint doesn't *own* its own • // 'name' value, the clients are at risk of memory corruption. • // • NamedPoint makeCityCoordinate (float x, float y, char *cityName, char *countryName) • { • char temp[80]; • sprintf (temp, "City: %s, Country: %s", cityName, countryName); • • return NamedPoint (x, y, temp); • } After I point out these problems, a typical fix is to modify NamedPoint to look like this (changes in bold): class NamedPoint { private: float x; float y; char *name; public: NamedPoint (float x, float y, char *name) { this->x = x; this->y = y; this->name = new char[strlen(name) + 1]; strcpy (this->name, name); } float getX() {return x;} float getY() {return y;} const char *getName() {return name;} void setX(float x) {this->x = x;} void setY(float y) {this->y = y;} void setName(char *name) {this->name = new char[strlen(name) + 1]; strcpy (this->name, name);} }; This trades in one set of bugs for another. The new version has the following problems: • It doesn't have a destructor, so it leaks memory. • setName() doesn't delete name, so it leaks more memory if setName() is called. • strlen(NULL) and strcpy(NULL) are bad. Usually, a program will crash if this is attempted, so we really should check for NULL. After I point this out, I usually get a third try that looks like this: class NamedPoint { private: float x; float y; char *name; public: NamedPoint (float x, float y, char *name) { this->x = x; this->y = y; if (name == NULL) this->name = NULL; else { this->name = new char[strlen(name) + 1]; strcpy (this->name, name); } } ~NamedPoint () { if (name != NULL) delete name; } float getX() {return x;} float getY() {return y;} const char *getName() {return name;} void setX(float x) {this->x = x;} void setY(float y) {this->y = y;} void setName(char *name) {if (this->name != NULL) delete this->name; if (name == NULL) this->name = NULL; else { this->name = new char[strlen(name) + 1]; strcpy (this->name, name); }} }; Things are slowly improving ... in the sense that the bugs are getting more and more subtle. It is also worth mentioning that over half of the candidates don't assign NULL to name if the input 'name' value is NULL, leaving the memory uninitialized. This really isn't a C++ issue. Failing to initialize pointers in C structs is equally bad. The new problems are: • NamedPoint allocates with 'new[]' but deletes with 'delete'. This may or may not work depending on the compiler. It seems to work fine for most current compilers, so I rarely comment on this. Still, it is incorrect. • Testing for NULL before calling delete is unnecessary (since 'delete 0' is defined to be harmless), but causes no damage other than slowing down the program slightly. • NamedPoint now trashes the heap if any NamedPoint objects are passed by value (like, for example, returning a NamedPoint object from a function). This is because the copy constructor that C++ gives us for free copies the 'name' pointer, but does not copy the contents. Now, calling the destructor on the first shared 'name' returns the memory to the heap (although the second copy will continue to use it, EVEN IF THE MEMORY GETS ALLOCATED TO SOME OTHER USE). Calling the destructor on the second shared 'name' probably corrupts the heap by deleting memory that was not, at that time, allocated (the second delete isn't required to corrupt the heap, but this is how most C++ heap managers work). • It has similar problems with the default assignment operator. After pointing out the copy constructor and assignment operator problems, the fourth try usually looks like the code below. But not always. Sometimes I need to explain to the candidates what a copy constructor and assignment operator are. Some candidates have strange beliefs about when you need to implement them. One candidate, for example, believed that copy constructors were needed for classes above some size threshold, but not needed for classes below that size threshold. I'll emphasise that I'm interviewing candidates with several years C++ experience who have already passes a phone screen. In any event, typical attempt number four: class NamedPoint { private: float x; float y; char *name; public: NamedPoint (float x, float y, char *name) { this->x = x; this->y = y; if (name == NULL) this->name = NULL; else { this->name = new char[strlen(name) + 1]; strcpy (this->name, name); } } ~NamedPoint () { if (name != NULL) delete name; } // NOTE: Most interviewees start with a signature // like this: // NamedPoint (NamedPoint copy) // NamedPoint (const NamedPoint & copy) { this->x = copy.x; this->y = copy.y; if (copy.name != NULL) { this->name = new char[strlen (copy.name) + 1]; strcpy (this->name, copy.name); } } NamedPoint & operator=(const NamedPoint & copy) { this->x = copy.x; this->y = copy.y; if (this->name != NULL) delete this->name; if (copy.name != NULL) { this->name = new char[strlen (copy.name) + 1]; strcpy (this->name, copy.name); } // Note that we haven't nulled out this->name, so // we can get a double-delete problem... } float getX() {return x;} float getY() {return y;} const char *getName() {return name;} void setX(float x) {this->x = x;} void setY(float y) {this->y = y;} void setName(char *name) {if (this->name != NULL) delete this->name; if (name == NULL) this->name = NULL; else { this->name = new char[strlen(name) + 1]; strcpy (this->name, name); }} }; This is almost correct! The big problems remaining are that the assignment operator doesn't check for assignment to itself, the copy constructor only partially copies if 'copy' has NULL for its name, and we still risk a double-delete via the assignment operator. If a program does try to assign one of these objects to itself, the object deletes its own 'name' value before attempting to copy it onto itself. I usually stop here (assuming we get this far). Conclusion Empirically, I have found it very difficult to find even experienced C++ programmers capable of correctly writing a simple C++ class containing a pointer. Since pointers are, because of the C legacy, an important part of the language, this is a fatal flaw for large projects that need to work. Summarizing the mistakes in my fairly trivial problem: • Pointer assignment (a C legacy) makes it too easy to corrupt the stack and heap. The initial solution allows the stack to be accessed after it has gone out of scope. Corrected versions often allow for double deletes of heap allocated storage or accessing already deleted heap storage or both. • The default copy constructor and assignment operator are too often wrong. But you get them unless you explicitly take action. The language default being fatally wrong is a big problem. • delete and delete[] are similar, but possibly different. • NULL is legal for many pointer values, but the behavior tends to be undefined (delete being one nice exception). Since the NULL case is frequently overlooked, memory corruption again seems to be designed in to large systems. One solution is to do a lot more stuff with things like STL string objects and generally try to hide the heap allocation. The auto_ptr<> and similar classes help here, too. But they only help. The fundamental problem still remains -- it is too easy to write subtly wrong code and the language is littered with booby-traps. Larger programs encounter even more tricky problems. Scott Meyers has written two book on the subject of not getting killed by the C++ language. My point, though, is that most experienced C++ programmers I have interviewed can't get a simple class correct, even after multiple tries. Enough said. It makes me unwilling to risk a large project with the language. http://dl.dropbox.com/u/1982439/CAE%20software%20development/Programming/Language%20arguments/Why%20I%20Dislike%20C%2B%2B%20For%20Large%20Projects.doc |
» 猜你喜欢
请问有评职称,把科研教学业绩算分排序的高校吗
已经有6人回复
2025冷门绝学什么时候出结果
已经有6人回复
Bioresource Technology期刊,第一次返修的时候被退回好几次了
已经有7人回复
真诚求助:手里的省社科项目结项要求主持人一篇中文核心,有什么渠道能发核心吗
已经有8人回复
寻求一种能扛住强氧化性腐蚀性的容器密封件
已经有5人回复
请问哪里可以有青B申请的本子可以借鉴一下。
已经有4人回复
请问下大家为什么这个铃木偶联几乎不反应呢
已经有5人回复
天津工业大学郑柳春团队欢迎化学化工、高分子化学或有机合成方向的博士生和硕士生加入
已经有4人回复
康复大学泰山学者周祺惠团队招收博士研究生
已经有6人回复
AI论文写作工具:是科研加速器还是学术作弊器?
已经有3人回复
» 本主题相关价值贴推荐,对您同样有帮助:
想出国读研,寻找意见,请求指教!!!
已经有7人回复
哈尔滨工业大学计算机科学与技术学院教师招聘启事
已经有3人回复


2楼2010-07-27 09:30:14
yalefield
金虫 (文坛精英)
老汉一枚
- 程序强帖: 3
- 应助: 129 (高中生)
- 贵宾: 0.17
- 金币: 21238.9
- 散金: 3440
- 红花: 66
- 帖子: 12101
- 在线: 759.1小时
- 虫号: 96063
- 注册: 2005-10-07
- 专业: 高等教育学
- 管辖: 计算模拟
3楼2010-07-27 23:15:18
cfem_nli
新虫 (初入文坛)
- 应助: 0 (幼儿园)
- 金币: 113.1
- 帖子: 22
- 在线: 67.2小时
- 虫号: 1062018
- 注册: 2010-07-22
- 性别: GG
- 专业: 爆炸与冲击动力学
★ ★
resonant(金币+2):维护费:-) 2010-08-10 21:12:48
resonant(金币+2):维护费:-) 2010-08-10 21:12:48
|
我想可能让你有所误会了。 首先呢,想说几句题外的话,历来的语言之争,其实乏味,大都是各领域的顶尖的一些人物,在那里宣传自己的种种好处,对我们来说,这样的争辩本身没有意思,但是呢,可以看到一些语言的基本的但是很深层次的东西,缺点或者是优点; 其次,如果要辩论,那么也是看应用背景,就是说我们要做什么样的应用开发,说白了,具体应用具体分析,没有大一统的语言 再三,稍微通用一些的层次上,比如说很多人包括我自己当时就问应该学什么语言好,如果说一定是要给点说法的话,那么,个人以为容易上手是一个首要的法则。就是说,对初学者,对一般层次的人,比如说本人,学的来,但是呢又不容易犯错。 关于我自己,其实非编程的科班出身,也不敢自认为高手,力学出身。做这样的思考,是因为当要作有限元软件开发的话,想比较比较那些语言在那些方面有优势,为什么现在的软件是现在这样的结构构成,等等问题。这样的背景,极有可能让我想问题的方式有偏颇,对语言的看法也来的不如程序高手那么直接和简洁,一语中的。 说了不少,回到先前的帖子上。英文原文的一些看法让我深以为然,两个原因,一个是:他涉及到了c++的构造函数,再一个是她说到的是项目开发的实际情况。对我己而言,不是编程特多,c++的构造函数很让我头疼,尤其是涉及到继承以后,构造函数很多类别,构造函数里的函数变量定义,初始化,exception handle,指针处理,不少的问题,让我感觉应付来有点头疼,觉着需要很多练习才行; 这是他说的第一个方面 。关于指针的话,我想,他没有提多少,但是估计让不少人构头疼的吧 第二个就是,实际做一个项目来说,就有很多的人来做。Top10 或者top20,在你的组里,是个好事,不过有一个差一些的也在做,那么可想而知你的麻烦事一定是源源不绝。很遗憾的是,那个造成这种局面的人往往意识不到那些潜在的错误。 至于说原帖那些都应该是c++的基础,或者说学过c++的人都该知道的,我不知道实际情况,我不知道怎么定义c++的基础内容。或许最好能做一个统计,看看大家常见的错误,或者令程序员们常常痛恨的错误,等等 但是并不是要来否定c++,linus说C++ Sucks,我不知道,没有他那么偏激。 欢迎有想的想法,欢迎指正。 |

4楼2010-07-28 08:09:12
cfem_nli
新虫 (初入文坛)
- 应助: 0 (幼儿园)
- 金币: 113.1
- 帖子: 22
- 在线: 67.2小时
- 虫号: 1062018
- 注册: 2010-07-22
- 性别: GG
- 专业: 爆炸与冲击动力学
顺便给出linus当时的关于c++ sucks争论的一个链接
|
首先呢,这个链接有点感觉是偏离主题了,只不过是我上面的帖子提到了这个,所以就权作为娱乐休闲,想看的朋友就关注一下 不想就这个作为讨论,实在是力不从心 我个人觉得之所以他那么偏激,可能一是他自己是一个c的fan,二是c当时是为系统开发而做的,可能就是适合linux kernel吧,印象中记得他说c++ 是在c上添枝加叶,尽做些不痛不痒的修改,说来说去,都不乏炒作之嫌 http://thread.gmane.org/gmane.comp.version-control.git/57918 why c++ sucks by linus |

5楼2010-07-28 08:29:13
tjyl
金虫 (正式写手)
- 程序强帖: 2
- 应助: 0 (幼儿园)
- 金币: 3218.1
- 红花: 2
- 帖子: 576
- 在线: 156.6小时
- 虫号: 765184
- 注册: 2009-05-07
- 专业: 生物无机化学
- 管辖: 程序语言
6楼2010-08-10 18:00:52













回复此楼