花時間通讀了下Meyers大神的著做《Effective c++》,其中受益不少,畢竟書中有不少東西是以前在寫代碼時徹底沒有考慮過的地方,做者用獨到的眼光來告訴咱們,c++不是一門簡單的編程語言,而是一門堆積埃菲爾鐵塔式程序的藝術。c++
接下來,讓我對書中的「條款」用本身的語言方式,做一些總結和我的心得批註。
(PS:其中帶「*」號的條款是本人不太理解或者使人可能較難理解的條款。對其中一些難以理解的條款我會給予詳細解釋,簡單條款將略過)編程
1.c++能夠分爲:(1)C (2)Object-Oriented C++ (3)Template C++ (4)STL。編程語言
2.儘可能用const,enum,inline代替#define,或者說,寧肯用編譯器代替預處理器。由於宏定義容易出錯(思考define函數進行運算時須要加上小括號)。函數
3.儘量用const定義常量。ui
4.肯定對象在使用前已先被初始化。特別對於構造函數,最好用成員初值列(member initialization list),而不是在構造函數內使用賦值。this
舉個例子:你有一個類A,那麼在定義構造函數時,最好這樣去初始化設計
cA:A(const string& name,const string& address, const list<PhoneNumber>& phones): theName(name), thePhones(phones), numTimesConsulted(0){}
這樣的話,你無需對構造函數內部自己進行任何動做。理由在於,對大多數類型而言,這樣比起調用默認構造函數高效許多。指針
5.瞭解c++默默編寫了和調用了哪些函數。code
就是好比說說你要清楚,c++在編譯時會拒絕哪些賦值動做,拒絕哪些?對於一個class,編譯器會默認爲類建立default構造函數、析構函數、copy構造函數、copy assignment操做符。對象
6.若不想用編譯器自動生成的函數,就拒絕他。好比,你能夠把一個類的複製構造函數放在private裏,在子類繼承他時,使用私有繼承,讓類uncopyable。
7.爲多態基類聲明virtual析構函數。
對於一個多態基類而言,應該對他聲明一個virtual析構函數,就是說,假如一個類帶有任何的virtual函數,咱們就應該讓他擁有一個virtual析構函數。
8.不要讓析構函數吐出異常。若是有必要,那麼在class中提供一個普通函數執行該操做。
9.絕對不要在構造和析構函數中調用virtual函數。
*10.令operatior=返回一個reference to *this。
cclass Widget{ ...... Widget& operator+=(const Widget& rhs) //返回類型是個reference,指向當前對象 { ... return *this; } ...... }
11.在operator=中處理「自我賦值」。你不能保證用戶不會讓對象作自我賦值這種看起來雖然愚蠢的事情。
*12.確保複製對象時沒有忘記他的每個成員。包括全部的公有與私有成員。
13.用對象來管理資源。
這裏推崇一個概念--RAII(Resource Acquisition Is Initialization),你在得到得到一個對象時,必須對他進行相應有效的管理,使用STL提供的auto_ptr或者shared_ptr能讓你更加輕鬆使用對象。推薦使用shared_ptr,無須擔憂複製動做帶來的麻煩。
*14.當心資源管理的copy行爲。
--對RAII對象作到禁止複製。
--對底層資源使用引用計數法(reference-count),好比在寫鎖操做時。
--對複製操做進行深拷貝(考慮堆的深複製)。
--轉移底層資源的全部權。當一個對象被複制,資源的擁有權將從被複制的對象轉移到目標對象上。
*15.在資源管理類中提供對原始資源的訪問。
16.new與delete時採用相同形式。
S *s1 = new S; delete S; S *s2 = new S[100]; delete []s2;
*17.以獨立語句將newed對象儲存於智能指針中。
int priority(); void processWidget(std::tr1::shared_ptr<Widget> pw, int priority); //如今調用processWidget processWidget(new Widget, priority());
如今你會發現這個代碼沒法經過編譯,由於tr1::shared_ptr須要一個原始指針,但他的構造函數是個explict構造函數。
如今你把他修改爲:
processWidget(std::tr1::shared_ptr<Widget>(new Widget), priority());
可是,這樣會有很大可能致使內存泄漏。
思考,當咱們對priority的調用失敗時,咱們沒法阻止內存泄漏的產生!
避免方案其實很簡單,就以下,用一個獨立語句拆分他。
std::tr1::shared_ptr<Widget> pw(new Widget); processWidget(pw, priority());
18.讓接口容易被正確使用,不易被誤用。
*19.設計class猶如設計type。
20.寧用pass-by-reference-to-const代替pass-by-value
class Person(){ public: Person(); virtual ~Person(); ... private: string name; string address; }; class Student():public Person{ public: Student(); ~Student(); ... private: string schoolName; string schoolAddress; }; bool validateStudent(Student s); Student plato; bool platoIsOk = validateStudent(plato);
當你用這個方法去傳遞一個Student對象時,整體成本是六次構造函數和六次析構函數。(本身算下string對象和student對象的創造過程)
(未完待續,最近實習入職,有時間繼續寫)