Effective C++ 3nd 读书摘要(一、让自己习惯C++ ; 二、构造,析构,赋值运算)Item1 - 12
2009-06-01 16:44
826 查看
一、让自己习惯C++
Item1. 视C++为一个语言联邦
C++由以下部分组成:C、Object-Oriented C++、Template C++、STL
Item2. 尽量以const、enum、inline代替#define
Item3. 尽可能使用const
1.一共有这样几种const用法:
char greeting[] = "Hello";
char *p = greeting; // non-const pointer, non-const data
const char *p = greeting; // non-const pointer, const data
char * const p = greeting; // const pointer, non-const data
const char * const p = greeting; // const pointer, const data
另外,以下两种形式是一样的:
void f1(const Widget *pw); // f1 takes a pointer to a constant Widget object
void f2(Widget const *pw); // so does f2
迭代器也有const:
const std::vector<int>::iterator iter = // iter acts like a T* const
std::vector<int>::const_iterator cIter = //cIter acts like a const T*
2. 让non-const函数调用const函数以避免重复:
const函数可以使得返回的const指针、const引用等等均可以调用一些方法(const对象只能调用const函数)
Item4. 确保对象在使用前已经先被初始化
重要的是不能混淆赋值(assignment)与初始化(initialization),通常后者的效率更高,初始化通过成员初值列表。最好以申明次序作为成员列表中的次序。
Singleton模式的一个应用:定义于不同编译单元的non-local static对象的初始化次序
即以local static对象代替non-local static对象
二、构造、析构、赋值运算
Item5. 了解C++默默编写并调用了哪些函数
这些是C++会默认生成的(如果你没有定义):copy构造、copy assignment、析构(non-virtual)、default构造,所有这些都是public而inline的。
(注:上面的析构(non-virtual),除非其base class是虚析构)
Item6. 若不想使用编译器自动生成的函数,就该明确拒绝
接Item5所言,要想拒绝之:
也可以建一个base class,这样还可以把连接期错误移到编译期:
我们只要继承自此类:
class HomeForSale: private Uncopyable { // class no longer
... // declares copy ctor or copy assign. operator
};
Item07. 为多态基类声明virtual析构函数
否则当用base class pointer来delete那个derived class对象时会造成局部销毁。
如果class带有任何virtual函数,base class就应该带有一个virtual析构函数。否则不该用。
Item08. 别让异常逃离析构函数
如果一个被析构函数调用的函数可能抛出异常,析构函数应该捕捉任何异常,然后吞下它们(不传播)或结
束程序。
较好的一种做法是:
给客户一次调用close处理错误的机会。
Item09. 绝不在构造和析构过程中调用virtual函数
因为在base class构造期间对象的类型还是base class而不是derived classe(此时的virtual函数不是virtual函数,而只是个base class的函数),derived class成分尚为未定义值。
同样,一旦derived class析构函数开始执行,对象内的derived class成员变量便呈现未定义值,那么当进入
base class析构函数后对象就成为一个base class对象。
一种弥补方法是令derived classes将必要的构造信息向上传递至base class构造函数。
Item10. 令operator=返回一个reference to *this
这样可以支持x=y=z=15这样的赋值连锁形式。
Item11. 在operator=中处理“自我赋值”
其中可以用到的技术有:
1. 比较“来源对象”和“目标对象”的地址 if(this == & rhs) return * this;
2. 精心周到的语句顺序
3. copy-and-swap
Item12. 复制对象时勿忘其每一个成分
1.要确保(1)复制所有local成员变量;(2)调用所有base classes内的适当的copying函数(copy constructor或copy assignment)
2.不要尝试以一个copying函数实现另一个copying函数,而应该将共同功能放进第三个函数中。
Item1. 视C++为一个语言联邦
C++由以下部分组成:C、Object-Oriented C++、Template C++、STL
Item2. 尽量以const、enum、inline代替#define
Item3. 尽可能使用const
1.一共有这样几种const用法:
char greeting[] = "Hello";
char *p = greeting; // non-const pointer, non-const data
const char *p = greeting; // non-const pointer, const data
char * const p = greeting; // const pointer, non-const data
const char * const p = greeting; // const pointer, const data
另外,以下两种形式是一样的:
void f1(const Widget *pw); // f1 takes a pointer to a constant Widget object
void f2(Widget const *pw); // so does f2
迭代器也有const:
const std::vector<int>::iterator iter = // iter acts like a T* const
std::vector<int>::const_iterator cIter = //cIter acts like a const T*
2. 让non-const函数调用const函数以避免重复:
const char& operator[](std::size_t position) const // same as before { ... return text[position]; } char& operator[](std::size_t position) // now just calls const op[] { return const_cast<char&>( // cast away const on op[]'s return type; static_cast<const TextBlock&>(*this) // add const to *this's type; [position] // call const version of op[] ); }
const函数可以使得返回的const指针、const引用等等均可以调用一些方法(const对象只能调用const函数)
Item4. 确保对象在使用前已经先被初始化
重要的是不能混淆赋值(assignment)与初始化(initialization),通常后者的效率更高,初始化通过成员初值列表。最好以申明次序作为成员列表中的次序。
Singleton模式的一个应用:定义于不同编译单元的non-local static对象的初始化次序
class FileSystem { ... }; // as before FileSystem& tfs() // this replaces the tfs object; it could be { // static in the FileSystem class static FileSystem fs; // define and initialize a local static object return fs; // return a reference to it } class Directory { ... }; // as before Directory::Directory( params ) // as before, except references to tfs are { // now to tfs() ... std::size_t disks = tfs().numDisks(); ... } Directory& tempDir() // this replaces the tempDir object; it { // could be static in the Directory class static Directory td; // define/initialize local static object return td; // return reference to it }
即以local static对象代替non-local static对象
二、构造、析构、赋值运算
Item5. 了解C++默默编写并调用了哪些函数
这些是C++会默认生成的(如果你没有定义):copy构造、copy assignment、析构(non-virtual)、default构造,所有这些都是public而inline的。
(注:上面的析构(non-virtual),除非其base class是虚析构)
Item6. 若不想使用编译器自动生成的函数,就该明确拒绝
接Item5所言,要想拒绝之:
class HomeForSale { public: ... private: ... HomeForSale(const HomeForSale&); // declarations only HomeForSale& operator=(const HomeForSale&); };
也可以建一个base class,这样还可以把连接期错误移到编译期:
class Uncopyable { protected: // allow construction Uncopyable() {} // and destruction of ~Uncopyable() {} // derived objects... private: Uncopyable(const Uncopyable&); // ...but prevent copying Uncopyable& operator=(const Uncopyable&); };
我们只要继承自此类:
class HomeForSale: private Uncopyable { // class no longer
... // declares copy ctor or copy assign. operator
};
Item07. 为多态基类声明virtual析构函数
否则当用base class pointer来delete那个derived class对象时会造成局部销毁。
如果class带有任何virtual函数,base class就应该带有一个virtual析构函数。否则不该用。
Item08. 别让异常逃离析构函数
如果一个被析构函数调用的函数可能抛出异常,析构函数应该捕捉任何异常,然后吞下它们(不传播)或结
束程序。
较好的一种做法是:
class DBConn { public: ... void close() // new function for { // client use db.close(); closed = true; } ~DBConn() { if (!closed) { try { // close the connection db.close(); // if the client didn't } catch (...) { // if closing fails, make log entry that call to close failed; // note that and ... // terminate or swallow } } private: DBConnection db; bool closed; };
给客户一次调用close处理错误的机会。
Item09. 绝不在构造和析构过程中调用virtual函数
因为在base class构造期间对象的类型还是base class而不是derived classe(此时的virtual函数不是virtual函数,而只是个base class的函数),derived class成分尚为未定义值。
同样,一旦derived class析构函数开始执行,对象内的derived class成员变量便呈现未定义值,那么当进入
base class析构函数后对象就成为一个base class对象。
一种弥补方法是令derived classes将必要的构造信息向上传递至base class构造函数。
class Transaction { public: explicit Transaction(const std::string& logInfo); void logTransaction(const std::string& logInfo) const; // now a non-virtual func ... }; Transaction::Transaction(const std::string& logInfo) { ... logTransaction(logInfo); // now a non-virtual call } class BuyTransaction: public Transaction { public: BuyTransaction( parameters ) : Transaction(createLogString( parameters )) // pass log info { ... } // to base class ... // constructor private: static std::string createLogString( parameters ); };
Item10. 令operator=返回一个reference to *this
这样可以支持x=y=z=15这样的赋值连锁形式。
Item11. 在operator=中处理“自我赋值”
其中可以用到的技术有:
1. 比较“来源对象”和“目标对象”的地址 if(this == & rhs) return * this;
2. 精心周到的语句顺序
Widget& Widget::operator=(const Widget& rhs) // unsafe impl. of operator= { delete pb; // stop using current bitmap pb = new Bitmap(*rhs.pb); // start using a copy of rhs's bitmap return *this; // see Item 10 }
3. copy-and-swap
class Widget { ... void swap(Widget& rhs); // exchange *this's and rhs's data; ... // see Item 29 for details }; Widget& Widget::operator=(const Widget& rhs) { Widget temp(rhs); // make a copy of rhs's data swap(temp); // swap *this's data with the copy's return *this; }
Item12. 复制对象时勿忘其每一个成分
1.要确保(1)复制所有local成员变量;(2)调用所有base classes内的适当的copying函数(copy constructor或copy assignment)
2.不要尝试以一个copying函数实现另一个copying函数,而应该将共同功能放进第三个函数中。
相关文章推荐
- effective c++之构造 析构 赋值运算
- Effective C++ <二>:构造,析构,赋值运算
- Effective C++ 3nd 读书摘要(八、定制new和delete)Item49 - 52
- Effective C++ 3nd 读书摘要(九、杂项讨论)Item53 - 55
- effective C++之构造、析构、赋值运算
- effective C++之构造、析构、赋值运算
- Effective C++ 3nd 读书摘要(三、资源管理 ;四、设计与声明;五、实现)Item13 - 31
- Effective C++之构造、析构、赋值运算
- effective C++——第二章:构造、析构和赋值(item11~item17)
- Effective C++ 3nd 读书摘要(六、继承与面向对象设计)Item32 - 40
- effective c++之让自己习惯C++
- C++构造与析构(12) - copy elision编译器优化
- C++对象的构造、赋值和析构
- Effective C++第一章 让自己习惯C++
- effective C++阅读笔记一——让自己习惯C++
- 深入理解C++构造、析构、赋值操作
- C++对象的构造、赋值和析构
- 【读书笔记】Effective C++-1 让自己习惯C++(之三)
- Effective C++ 1.让自己习惯C++
- Effective C++ 精要(第二部分:构造、析构和赋值)