Effective C++ 读书笔记之Part1.Accustoming Yourself to C++

1、View C++ as a federation of languages

C++的四个次语言:

1)C

2)Object-Oriented C++

3)Template C++

4)STL

2、Prefer consts, enums, and inlines to #defines

一方面是因为使用宏定义不利于调试的时候定位错误,另一方面主要是因为预处理器和编译器两者分工不同所导致的。

同时,宏定义太复杂的情况下很容易出现错误。

总结:

第一,对于单纯常量,最好以const对象或enums替换#defines.

第二,对于形似函数的宏(macros),最好改用inline函数替换#defines。

3、Use const whenever possible

const 语法虽然变化多端,但并不莫测高深。如果关键字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

如果被指物是常量,有些程序员会将关键字const 写在类型之前,有些人会把
它写在类型之后、星号之前。两种写法的意义相同,所以下列两个函数接受的参数
类型是一样的:
void f1(const Widget* pw);
void f2(Widget const * pw);
两种形式都有人用,你应该试着习惯它们。

STL 选代器系以指针为根据塑模出来,所以迭代器的作用就像个?指针。声
明选代器为 const 就像声明指针为 const 一样(即声明一个T* const 指针) ,表
示这个迭代器不得指向不同的东西,但它所指的东西的值是可以改动的。如果你希
望迭代器所指的东西不可被改动(即希望STL 模拟一个 const T* 指针) ,你需要
的是 const _iterator:
std::vector<int> vec;
const std::vector<int>::iterator iter = vec.begin( );  //iter的作用就像个T* const
* iter = 10;                                                                    //没有问题,改变iter所指物
++iter;                                                                           //错误,iter是const
std: :vector<int>::const iterator clter = vec.begin( );   //cIter的作用像是个const T *

*clter = 10;                                                                       //错误,*cIter是const

++clter;                                                                             //没问题 

总结:

第一,某些东西声明为const 可帮助编译器侦测出错误用法。const 可被施加于任何作用域内的对象、函数参数、函数返回类型、成员函数本体。
第二,编译器强制实施 bitwise constness ,但你编写程序时应该使用"概念上的常量性"
(conceptual constness)。
第三,当 const 和 non-const 成员函数有着实质等价的实现时,令 non-const 版本调

用 const 版本可避免代码重复。

4、Make sure that objects are initialized before they're used

     所谓 static 对象,其寿命从被构造出来直到程序结束为止,因此 stack 和heap-based 对象都被排除。这种对象包括 global 对象、定义于 namespace 作用域内的对象、在 classes 内、在函数内、以及在 file 作用域内被声明为 static 的对象。函数内的 static 对象称为 local static 对象(因为它们对函数而言是 local) ,其他 static对象称为 non-local static 对象。程序结束时 static 对象会被自动销毁,也就是它们的析构函数会在main
()结束时被自动调用。

        所谓编译单元<translation unit)是指产出单一目标文件 (singleobject file) 的那些源码。基本上它是单一源码文件加上其所含入的头文件(#include files) 。

总结:

第一,内置型对象进行手工初始化,因为 C++不保证初始化它们。
第二,构造函数最好使用成员初值列 (member initialization list) ,而不要在构造函数本体内使用赋值操作(assignment) 。初值列列出的成员变量,其排列次序应该和它们在 class 中的声明次序相同。

第三,为免除"跨编译单元之初始化次序"问题,请以local static 对象替换 non-local static 对象。

感悟:

从这部分的内容大致可以看出整本书的风格,主要是在多种可以实现的情况下告诉你哪种情况更加合适,更加可以避免错误。从而让读者的水平从对C++的一般理解进入到更深的层次。所列的点都是平时容易遇到的。必须要有一定的C++实践经验才读出效果,否则看完了也记不住。跟实践经验很少的人直接去读设计模式是一个效果。

时间: 2024-11-03 10:55:57

Effective C++ 读书笔记之Part1.Accustoming Yourself to C++的相关文章

More Effective C++ 读书笔记五——异常

条款12:了解"抛出一个exception"与"传递一个参数"或"调用一个虚函数"之间的差异 第一,exception object总是会被复制,如果以by value方式捕捉,它们甚至被复制两次.至于传递给函数参数的对象不一定得复制.第二,"被抛出成为exceptions"的对象,其被允许的类型转换动作,比"被传递到函数去"的对象少.第三,catch子句以其"出现于源代码的顺序"被编译

More Effective C++ 读书笔记二

条款4:非必要不提供default constructor 这里主要是列举下默认构造函数的优点和缺点. 如果没有默认构造函数,定义对象数组会比较麻烦,因为对象数组初始化的时候没法传递非默认构造函数的值,如果要使用,书中提到的方法是给数组每个变量初始化的时候调用构造函数,另一个就是使用指针数组. 第一个的缺点很明显,没法声明类似A a[10];这样的数组,在堆上申请,还得用到placement new这个之前没讲过的东西,另外还得一个个去初始化:后者的缺点当然是,数组里面的每个指针都需要记得去de

Effective C++ 读书笔记之Part6.Inheritance and Object-Oriented Design

32.Make sure public inheritance models "is-a". 所谓的最佳设计,取决于系统希望做什么事,包括现在与未来. 需要解决的问题:其中关于两个assert都通过的地方有些疑惑. 总结: "public继承"意味着is-a.适用于base classes身上的每一件事情一定也适用于derived classes身上,因为每一个derived class对象也都是一个base class对象. 33.Avoid hiding inh

More Effective C++ 读书笔记六——临时对象

条款19:了解临时对象的来源 c++真正的所谓的临时对象是不可见的--不会再你的源代码中出现.此等匿名对象通常发生于两种情况:一是当隐式类型转换(implicit type conveersions)被施行起来以求函数调用能够成功:二是当函数返回对象的时候. 第一种情况的例子: [cce lang="cpp"] #include <iostream> class Int { public: Int(int value) { _value = value; std::cout

More Effective C++ 读书笔记四——异常

条款9:利用destructors避免泄漏资源 这里开始介绍了auto_ptr,其实就是利用了c++局部对象在离开作用域的时候,其析构函数会被调用,来避免资源泄漏.这样的好处,就是不管是作用域正常结束(跑出代码块)还是异常结束(抛出异常),对象的析构函数都能保证被调用. 条款10:在constructors内阻止资源泄漏 c++只会析构已构造完成的对象.对象只有在其constructor执行完毕才算是完全构造妥当. 也就是说,c++不自动清理那些"构造期间抛出exceptions"的对

More Effective C++ 读书笔记三

条款8:了解各种不同意义的new和delete 这里讲了3种new,分别是:new operator, operator new, placement new. new operator最简单,它就是我们平时常用的new关键字,需要注意的是,它是不能被重载的.new operator的语义是先分配内存,然后调用对象的构造函数. operator new:这个是这三个new里面唯一能够重载的,平时我们重载的就是这个操作符.它的声明是: [cc lang="cpp"] void *oper

Effective C++ 读书笔记之Part2.Constructors, Destructors, and Assignment Operators

5.Know what functions C++ silently writes and calls. 总结:编译器可以暗自为class创建default构造函数.copy构造函数.copy assginment操作符,以及析构函数.这些函数都是public的,并且是inline的. 6.Explicitly disallow the use of compiler-generated functions you to not want. 总结:为驳回编译器自动(暗自)提供的机能,可将相应的成

Effective C++ 读书笔记之Part5.Implementations

 26. Postpone variable definitions as long as possible. 总结: 尽可能延后变量定义式的出现.这样做可增加程序的清晰度并改善程序效率. 批注: 纯C语言此处有冲突,C语言要求变量定义出现在代码快的开始部分. 27. Minimize casting. 1)const_cast 通常被用来将对象的常量性转除(cast away the constness) .它也是唯一有此能力的 C++-style 转型操作符. 2)dynamic_cast主

Effective C++ 读书笔记之Part8.Customizing new and delete

49. Understand the behavior of the new-handler. 总结: 第一,set_new_handler允许客户指定一个函数,在内存分配无法获得满足时被调用. 第二,Nothrow new是一个颇为局限的工具,因为它只适用于内存分配:后继的构造函数调用还是可能抛出异常. 50. Understand when it makes sense to replace new and delete. 替换编译器提供的operator new或operator dele