花时间通读了下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对象的创造过程)
(未完待续,最近实习入职,有时间继续写)