| 6 | 1/1 | 返回列表 |
| 查看: 1864 | 回復: 5 | |||
cfem_nli新蟲 (初入文壇)
|
[交流]
【分享】在大的項目中為什么不用c++[也順便測試一下你的c++基本水平] 已有4人參與
|
|
語言之爭歷來有之,可謂是經(jīng)久不息. 大一統(tǒng)的原則在這里并不適用. 對于科學計算, 很多人一直在為c++做宣傳,為其翻身. 可是c++本身的缺點也是顯而易見的,太過于復雜,一個優(yōu)秀的c++程序員實在是不好找. 轉(zhuǎn)載一篇很久以前看到的文章, 從電腦里翻出來,忘了出處了, 哪位要是知道麻煩廣而告之. 看著篇文章,也順便測試一下你的c++基本水平. 這是英文原文,后面附帶了鏈接,可以下載.沒有時間做適當?shù)姆g,如果哪位仁兄實在有此需要的話,我再盡量找時間補上;要是有人能夠翻譯了,在這里先行謝過了. 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 |


金蟲 (文壇精英)
老漢一枚
新蟲 (初入文壇)
|
我想可能讓你有所誤會了。 首先呢,想說幾句題外的話,歷來的語言之爭,其實乏味,大都是各領域的頂尖的一些人物,在那里宣傳自己的種種好處,對我們來說,這樣的爭辯本身沒有意思,但是呢,可以看到一些語言的基本的但是很深層次的東西,缺點或者是優(yōu)點; 其次,如果要辯論,那么也是看應用背景,就是說我們要做什么樣的應用開發(fā),說白了,具體應用具體分析,沒有大一統(tǒng)的語言 再三,稍微通用一些的層次上,比如說很多人包括我自己當時就問應該學什么語言好,如果說一定是要給點說法的話,那么,個人以為容易上手是一個首要的法則。就是說,對初學者,對一般層次的人,比如說本人,學的來,但是呢又不容易犯錯。 關于我自己,其實非編程的科班出身,也不敢自認為高手,力學出身。做這樣的思考,是因為當要作有限元軟件開發(fā)的話,想比較比較那些語言在那些方面有優(yōu)勢,為什么現(xiàn)在的軟件是現(xiàn)在這樣的結構構成,等等問題。這樣的背景,極有可能讓我想問題的方式有偏頗,對語言的看法也來的不如程序高手那么直接和簡潔,一語中的。 說了不少,回到先前的帖子上。英文原文的一些看法讓我深以為然,兩個原因,一個是:他涉及到了c++的構造函數(shù),再一個是她說到的是項目開發(fā)的實際情況。對我己而言,不是編程特多,c++的構造函數(shù)很讓我頭疼,尤其是涉及到繼承以后,構造函數(shù)很多類別,構造函數(shù)里的函數(shù)變量定義,初始化,exception handle,指針處理,不少的問題,讓我感覺應付來有點頭疼,覺著需要很多練習才行; 這是他說的第一個方面 。關于指針的話,我想,他沒有提多少,但是估計讓不少人構頭疼的吧 第二個就是,實際做一個項目來說,就有很多的人來做。Top10 或者top20,在你的組里,是個好事,不過有一個差一些的也在做,那么可想而知你的麻煩事一定是源源不絕。很遺憾的是,那個造成這種局面的人往往意識不到那些潛在的錯誤。 至于說原帖那些都應該是c++的基礎,或者說學過c++的人都該知道的,我不知道實際情況,我不知道怎么定義c++的基礎內(nèi)容;蛟S最好能做一個統(tǒng)計,看看大家常見的錯誤,或者令程序員們常常痛恨的錯誤,等等 但是并不是要來否定c++,linus說C++ Sucks,我不知道,沒有他那么偏激。 歡迎有想的想法,歡迎指正。 |

新蟲 (初入文壇)
|
首先呢,這個鏈接有點感覺是偏離主題了,只不過是我上面的帖子提到了這個,所以就權作為娛樂休閑,想看的朋友就關注一下 不想就這個作為討論,實在是力不從心 我個人覺得之所以他那么偏激,可能一是他自己是一個c的fan,二是c當時是為系統(tǒng)開發(fā)而做的,可能就是適合linux kernel吧,印象中記得他說c++ 是在c上添枝加葉,盡做些不痛不癢的修改,說來說去,都不乏炒作之嫌 http://thread.gmane.org/gmane.comp.version-control.git/57918 why c++ sucks by linus |

金蟲 (正式寫手)
| 6 | 1/1 | 返回列表 |
| 最具人氣熱帖推薦 [查看全部] | 作者 | 回/看 | 最后發(fā)表 | |
|---|---|---|---|---|
|
[考研] 求調(diào)劑 +3 | 圖鑒212 2026-03-30 | 3/150 |
|
|---|---|---|---|---|
|
[考研] 277跪求調(diào)劑 +8 | 1915668 2026-03-27 | 12/600 |
|
|
[考研] 289求調(diào)劑 +16 | 新時代材料 2026-03-27 | 16/800 |
|
|
[考研] 329求調(diào)劑 +8 | 星野? 2026-03-26 | 8/400 |
|
|
[碩博家園] 求調(diào)劑 有機化學考研356分 +10 | Nadiums 2026-03-25 | 11/550 |
|
|
[考研] 生物技術與工程 +7 | 1294608413 2026-03-25 | 8/400 |
|
|
[考研] 一志愿中南大學化學0703總分337求調(diào)劑 +6 | niko- 2026-03-27 | 6/300 |
|
|
[考研] 一志愿211,335分,0856,求調(diào)劑院校和導師 +7 | 傾____蕭 2026-03-27 | 8/400 |
|
|
[考研] 275求調(diào)劑 +15 | Micky11223 2026-03-25 | 20/1000 |
|
|
[考研] 343求調(diào)劑 +6 | 愛羈絆 2026-03-29 | 6/300 |
|
|
[考研] 11408軟件工程求調(diào)劑 +3 | Qiu學ing 2026-03-28 | 3/150 |
|
|
[考研] 085602 化工專碩 338分 求調(diào)劑 +12 | 路癡小琪 2026-03-27 | 12/600 |
|
|
[考研] 一志愿南京航空航天大學材料學碩求調(diào)劑 +3 | @taotao 2026-03-28 | 3/150 |
|
|
[考研] 331環(huán)境科學與工程求調(diào)劑 +3 | 熠然好運氣 2026-03-27 | 3/150 |
|
|
[考研] 330一志愿中國海洋大學 化學工程 085602 有讀博意愿 求調(diào)劑 +3 | wywy.. 2026-03-27 | 4/200 |
|
|
[考研] 一志愿211院校 344分 東北農(nóng)業(yè)大學生物學學碩,求調(diào)劑 +5 | 丶風雪夜歸人丶 2026-03-26 | 8/400 |
|
|
[考研] 考研調(diào)劑 +10 | 呼呼?~+123456 2026-03-24 | 10/500 |
|
|
[考研] 341求調(diào)劑 +7 | 青檸檬1 2026-03-26 | 7/350 |
|
|
[考研] 290分調(diào)劑求助 +3 | 吉祥止止陳 2026-03-25 | 3/150 |
|
|
[考研] 考研一志愿蘇州大學初始315(英一)求調(diào)劑 +3 | sbdksD 2026-03-24 | 4/200 |
|