C++ 有哪些缺點?

有相當一部分人對 C++ 是又愛又恨。那麼應該有一些 C++ 自身的原因導致他的使用者(這裡指的是熟練的使用者)對它有所不滿。

提問的目的是試圖通過獲得一些觀點,嘗試設計一種比 C++ 更少陷阱的語言。因此,類似 C++ 對 C 的兼容這種歷史原因的做法,不被視作缺點。


C++ 的函數重載決議規則是所有語言中最複雜的,因為他允許用戶以兩種方式自定義隱式類型轉換。

比如有下面兩個函數:

Employee* findEmployee(const std::string surname, const std::string givenName, bool retired = false);
Employee* findEmployee(const std::string fullName, bool retired = false);

那麼

Employee* e = findEmployee("Chen", "Shuo");

對應哪個?

如果原來代碼里只有第一個函數,現在有人新增了第二個重載,會造成什麼後果?


這樣的問題最適合隨便亂侃大山了,甚至可能都答不到問題的點上,因為侃著侃著就會亂說了。

C++很複雜,這門語言有太多的誘惑,程序員需要極度的自律。而C++設計成這樣也是因為Bjarne說過他不希望把自己任何的喜惡都加在語言上,他希望程序員自己去判定,完全信任程序員。然而,信息時代發展到現在了,程序員也已經不像80,90時代一樣,似乎是少數人才可以做得事情,現在可以寫冒泡排序都可以找到一個編程開發工作,不需要理解計算機組織,不需要理解操作系統等等。而由於計算機基礎的缺失,這樣的程序員卻往往是需要語言來幫助規範的,需要語言幫他選擇,而非他來選擇語言的特性。而這樣的發展也是必然,如互聯網時代,很多時候就是需要可以快速構建搶佔市場,所以需要很快的搭建出來可運行的業務,而這時候很多情況下會選擇動態語言。當然,這樣很多時候也會有代價,當達到很大規模時,會回過頭藉助Native的語言,如C++,而Herb也發表過Why C++的Presentation:https://www.youtube.com/watch?v=xcwxGzbTyms 不過很多企業還沒有達到這樣的規模就消失在塵埃中了......

也正是這樣,C++具有著很大的複雜性,融合OOP,GP等各種編程範式於一身,而這也是對新手不利的地方。雖然現在的C++已經進化了,C++11/14對於新手來說已經算友善了,少了很多歷史殘留的坑,但是C++發展的路途增加新特性也是對新手的更大學習負擔,如增加的右值引用,std::move,std::forward到底又是什麼東西?

C++的複雜性也體現在類型系統上,不知道多少人都被C++的隱式類型轉換給弄的頭昏腦脹,如為什麼會有bool轉換這樣的東西。同時,加入了泛型編程和右值引用後,那麼類型推導也變得複雜。如:

template&
void f(T param);

Object o;

f(o); // param type is lvalue reference

f(std::move(o)) // param type is rvalue reference

為什麼明明是T,卻會讓我的類型推導出不同的類型,這個時候對於初次接觸的人都是不解。以前有句話叫做沒有讀過Effective C++的C++程序員不應該讓他開發,我覺得這句話現在也可以引申為沒有讀過Effective Modern C++的C++程序員不應該讓他開發,因為這本書寫的真的很好很透徹,而這本書就詳細解釋了這個例子的原因。

下面我想說說上面幾個用戶提到的問題,如模塊化系統,編譯慢,ABI,異常等問題。

的確,C++在不斷的進化,在不斷的改善,也同時增加了新手的學習。如上面有人談到C++沒有模塊系統,編譯慢的問題,而C++17有一篇提案講述的正是這個,叫做Module System,簡單的語法:

Module M; // Module Declaration

// Export Interface to client
export
{
int foo(){return 47;}
};

void bar() {}

import std.vector; // #include &
import M;

using namespace std;

int main()
{
vector& v;
foo();
bar(); // oops!
}

而這篇提案也提到了有用戶答的私有成員問題,如在Module M聲明的foo是可見的,而bar則是完全不可見,而遠非私有成員的不可訪問,但可見。

而其實大家痛苦的很多地方,C++標準委員會的人也不是不知道,如ABI的問題,也有提案說想要做一個標準,這篇提案是微軟的Herb提出的: https://isocpp.org/files/papers/n4028.pdf 而前一篇的Module System深得Bjarne的喜歡,而通過的幾率其實也是蠻大的了,而Herb這篇我不知道,說不定也已經被斃了,只是我不知道。

對於異常,大家都在討論用不用,而我前段時間也去研究過異常,把整個異常的實現都走通了一遍,我感嘆著編譯器實現異常的有趣,如try throw是如何一步一步的被Runtime捕獲,異常的類型信息是如何插入到表,landing pad 的選取等 Exception Handling in LLVM。可是,對於用戶來說,是否真的需要異常呢?我曾在一個回答中說C++的異常是很雞肋的東西,或者說的更直白點,要用好C++的異常不容易,不是無腦的try throw就好,C++也不會像Java一樣會強制要求你,C++的設計就是程序員自己做主。

而上面同樣說到沒有Metadata,沒有反射。而C++17也在考慮加入反射。是的,正如C++標準委員會之前定的計劃一樣,C++11是大改動,C++14小修改,C++17又是大改動。

總體來說,C++真的很複雜,或許現階段還有ABI,還有編譯鏈接模型,還有類型系統,模塊系統等的問題,其實C++也許都可以解決,但是解決完後又變複雜了,因為要保持與之前的兼容,還要保證高性能這一根本立足點,這真是對智力的一大考驗啊,所以我一直在說C++標準委員會的人都蠻碉的,比如C++11提出的Memory Model,真是把能抽象剝離的都抽象剝離出來了,很精細。

我是很喜愛C++的,更是Bjarne的腦殘粉,也靠著C++在吃飯。我很欣喜的看著C++不斷的變好,但是也必須承認C++還有很多不足,如很多知友和我上面提到的很多問題都的確是客觀存在的。


連引用都有三種的語言。。。


c++的第一個缺點1 就是因為兼容c,帶來風格上的不一致。

缺點2,c++沒有反射和內省,導致有時候用起來麻煩,比如操作資料庫,會有大量的手工代碼。

另外很多人語病的,沒有gc,我不認為是什麼缺點,我自己寫的c++程序,很少直接使用new和delete,一般交給stl管理了,或者使用make_shared處理了。

另外一個stl帶來的內存碎片,從語言層面來說,不是什麼缺點,因為所有語言都會有內存碎片的問題,只是有些帶gc的語言內置實現了內存池,比如python,對於c++這種要求適應各種環境的開發語言來說,內置內存池是不現實的(顯然大多數客戶端軟體並不需要內存池),內存碎片應該從設計層面解決,而不是語言層面解決,且stl本身也提供了解決方法。

還有一個所謂的二進位兼容問題,主要是開發組件的商業公司需要,windows上有com/winrt組件幫你解決,linux上基本都是開源的,並且gcc/clang編譯出來的大多數庫不存在二進位兼容問題(以後難說),二進位兼容問題並不迫切。

總結來說,c++的最大缺點是,太靈活,導致複雜(這裡複雜是指設計上的多樣性),但也是最大優點,從不會給你在軟體設計上套上任何枷鎖。


其實現在感覺用起來感到十分明顯的缺點並不來自c++本身,正如藍色大大所言,語言上的缺點其實都不是問題,天塌下來,有語言標準委員會頂著.真正到達應用起來的時候,需要注意的地方已經少了許多.而且我秉承的一貫開發模式就是設計的複雜,用的開心.stl也是如此.

我覺得更多的缺點是在於學習曲線的陡峭造成的從業者能力參差不齊,比如我經常被同事吐槽寫出看不懂的代碼(事實證明我只是為了安全和易用在折磨自己),再比如有一些不明真相的小白盲目的崇拜類似Google style這樣的「標準」,踏馬的,裡面一句singleton產生互相依賴就讓它內存泄露,讓我對這份標準黑到死,一個朋友說,至少那份標準我有一半在反對,我可能比他水平差點,我反對25%,c++就是這樣,能產生出各種性格迥異的程序員,不服就干.還有一些自認為是c++程序員的人,根本就不讀書,還覺得自己特牛逼,如果c++能屏蔽這部分人,不讓這幫丫挺的出來禍害人,那就是完美.


文法太混亂了..好像最近Dconf就說..不好做靜態分析


看了一下C++ FQA,感覺裡面雖然有些偏激,但還是有不少非常深刻的內容。

1:C++沒有很好地做到隱藏私有成員。私有成員必須要被寫在頭文件里,因為需要它們來計算類型的尺寸。

2:C++沒有包、模塊的概念,只有頭文件。可以認為1也是這個問題的部分體現。

3:C++提供的運行時特性非常貧乏,只有那個簡陋的RTTI。實際上,複雜到需要C++的系統,通常都已經複雜到了需要那些運行時的動態特性,比如反射。C++那種試圖把一切東西在編譯時定死的思想,我是不認同的。

至於那些坑太多一類的問題,就更不用提了。。。

我還是覺得可以把C++砍成兩個語言,一個是C with template,另一個是加上RTTI、反射、所有對象引用計數的「高級」語言。

再補充幾個有時可以部分替代C++的語言:D,Go,Rust,Vala,C#


最大的幾個問題:

1. 各編譯器 ABI 不統一;

2. 對象模型有缺陷,不像別的面相對象語言有 metaclass,以及從 Object 根對象的樹狀繼承關係,導致缺乏很多運行時特性;

3. 缺少內建 GC。


這個問題屬於老生長談的問題

C++的生存空間正在被大大的擠壓,現在有一種很普遍的認識就是C++在做底層不如C,在做企業應用又做不過java,確實現在的現狀令C++的前途堪憂,C++的設計的初衷在很大程度是為了彌補C在面向對象的不足,但是設計使得其語法過於繁瑣,相比與java,.net,python,ruby這樣的語言,它實在是太重了

我個人在使用C++的使用有非常多的困惑,我歸結大致有這幾點:

  1. OOP方面的困惑,比如虛函數,繼承等問題

  2. 指針和引用的困惑,到底什麼時候用指針還是引用,這點也是相當的困惑,你會發現有些函數的介面提供的參數提供的指針,有的提供的是引用,這些地方是大用可深究之處的
  3. 類型轉換,這點也是另很多初學者困惑的地方,一不小心就會讓你的程序踩到陷阱
  4. 天書般的的模板和元編程,會讓才接觸的初學者相當困惑,早年我曾經閱讀過俄羅斯人寫的一個關於svg的GDI+庫,裡面幾乎全是類模板,看了讓你淚奔
  5. 內存釋放,雖然可控性強,但是帶來的問題很多,程序寫大了,這個問題就更是非常難避免,即使有智能指針但是也不能解決所有的問題

關於C++的詬病,Linus Torvalds以前也是噴了不少,特別是他比較了C和C++

不過以C ++聞名於世的Andrei Alexandrescu,我記得在08年來過中國,接受csdn的採訪,當被問到C++的前途,他引用了scott meyer的一段表述,你看現在什麼語言寫的軟體是最賺錢的,呵呵,答案是微軟的office,office就是C++寫的,不過現在這個傢伙正在和其他幾位C++大佬在推D語言,當然有一個很明確的目的是改進C++

總而言之,C++學習的成本很大,難度也最大,要學好真的不簡單,C++的門徒都是在一堆的困惑中前進的


補充一個資料,感覺還不錯

C++ Frequently Questioned Answers

雖然那個FQA有點老了,很多也有不錯的解決方法了,不過總的來說肯定比我寫得好。

下面是原答案

------------------------------

1、編譯慢。當年寫C++的時候,小項目編譯的時候可以吃一個冰棍了。。當然可以用ccache和distcc

2、人員混雜,會的不會的都說精通C++,很難在開始篩選人。

3、沒有abi,所有的庫基本上一個編譯器就要有一個二進位。。。看看Qt就知道了,裝一個windows版本的Qt,所有的編譯器都覆蓋到能有幾個G了

4、exception基本上不可用。

話說,居然沒人說編譯慢這個問題。。我覺得這才是我不喜歡Cpp的根本問題。。。


1. C++在多線程情況下,如果不用Actor模型,對象的生命周期管理簡直是噩夢

2. 用異常來處理錯誤?你見過整個伺服器程序每個函數都用try/catch包一下的寫法嗎,對於沒有正確理解exception的人來說,c++的異常最好的用法就是只在main函數中用

3. 對象之間的交互可用的模型太多,listener, callback, message, bind function, 導致不同開發者之間思維習慣大大不同


這幾天整天因為這個編譯不過:

boost::python::object tuple(boost::python::handle&<&>(_kv_tuple));

C++把這句話當成了個函數聲明= =,沒辦法多加了個括弧...

boost::python::object tuple((boost::python::handle&<&>(_kv_tuple)));

gcc的鬼錯誤提示,完全看不出來哪裡錯了。


不能說更「好用」,只能說在合適的層面使用更合適的語言更佳。在較高封裝層次使用py/lua等作為oop開發比較省力,我會喜歡多個語言結合使用,充分發揮各自的優點來完成一個作品,單純用一個語言就想搞好各種東西是不靠譜的。至於說C++的缺點,在較高層次下使用真的很不方便,遠不如py


努力在更高層面做設計開發,卻又被低層細節所累(典型的如內存管理,字元串處理)。

一旦接收了C++中的OOP,就上了船了,要實現一個能融入C++類型系統的「完美」的class是何其繁瑣。

語法很臟(一部分拜兼容C所賜,一部分源於支持多范型,還有一部分源於設計理念:不替開發者做選擇,而追求無限的靈活性)。

比C++更好用的語言?我找到一個:Go語言。


標準委員會動作太慢,語言進化太慢!

C++ 98 ,11,14,17...

想想你想要什麼,又看了看都加了些什麼,我摔!一討論就是三年啊!而且才加那麼幾個東西!

好不容易標準出來了,想跨平台,各家編譯器實現又得三年!

編譯器實現完了,大神開始出書開始普及又是三年!

現在都2016年了!C++11的特性我還沒法用全,因為編譯器還沒有實現完全啊!!!

C++的缺點充分證明了我dang的優越性啊~看看人家C#,開疆擴土的速度,嘖嘖,至少年年都有糖發啊!


簡單來說,C++的根本問題就是,當你試圖去解決一些C++本身解決不了的問題的時候,所引入的解決方案往往會帶來更多的問題。

實際上比C++好用的語言多的是,不能理解嘗試設計這樣一門語言的意義何在?如果只是作為練習,那麼是否比C++好用根本沒有必要作為考慮因素。

所有這些比C++更好用的語言,相比C++有兩個主要缺陷:

1.性能;

2.路徑依賴;

缺陷1在某種程度上已經不能算作是缺陷,性能有時不僅僅依賴於語言的好壞,還依賴於編譯器和解釋器的能力。現在已經出現一些編譯器能編譯出性能上媲美C++的目標代碼,比如V8。但對於某些高可靠性的領域,C++還是有無可替代的優勢。在這些領域,人的成本不是最高的。

缺陷2才是阻礙其它語言發展的真正因素。


陷阱太多

太複雜

對初學者不友好

編譯器對標準的支持差異大

標準庫實現質量參差不齊

標準還在大規模演進

可以被越來越多的其他語言組合取代


缺點就是太複雜,我學不會!


我覺得,C++之所以寫的痛苦,是因為那些人的潔癖太多了。你看我www.gaclib.net的代碼,把C++寫得跟C#一樣,而性能幾乎又沒有什麼看得見的下降,該抽象就抽象,該底層就底層,豈不快活?所以說,煩惱都是自找的。


尼瑪我覺得所有的其他回答都沒有說到重點。

我個人覺得C++的主要缺點是:

吸引了一群完美沒有能力駕馭,卻又自命不凡的碼農去用它。

語言的設計,如果一開始就把「避免犯錯」放到第一位,那麼這種語言可能不是一種性能好的語言,但一定會是種生產力很高的語言(也就是最能為人類創造價值)。

不服來戰。


推薦閱讀:

if嵌套的代碼風格哪種好?
你有哪些想要分享的 PyCharm 使用技巧?
你見過哪些令你瞠目結舌的 Python 代碼技巧?
Windows 的 file handle 為什麼譯為「文件句柄」?
你見過哪些令人瞠目結舌的php代碼技巧?

TAG:編程語言 | 編程 | C |