08 2015 档案
摘要:1. 如果变量定义得过早,那么如果在变量定义后被用到之前出现异常,变量未被用到,但仍然要承担构造和析构成本,此外变量用时再定义也便于查找变量,增加代码可读性.2. 对于循环,除非赋值成本比构造和析构成本低且程序对效率高度敏感,将变量定义放在循环内部可以限制变量作用域,增强程序的可理解性和易维护性.
阅读全文
摘要:1. swap是STL的一部分,后来成为异常安全性编程(exception-safe programming)(见条款29)的一个重要脊柱,标准库的swap函数模板定义类似以下:namespace std{ template swap(T& lhs,T& rhs){ T t...
阅读全文
摘要:1. 通常,将只接受拷贝构造函数声明为explict是一个不错的主意,因为这可以避免自动的隐式类型转换所带来的错误,但有些情况下,使类支持隐式类型转换是可行的,例如自定义的数值类型:class Rational{public: Rational(int numerator=0,int deno...
阅读全文
摘要:1. 面向对象的真实意义并非是数据以及操作数据的函数应该被捆绑在一起,而是要求数据应该尽可能地被封装.封装意味着数据的不可见,越多的东西被封装,用户对其直接的接触就越少,用户代码和被封装内容的编译相关度就越低,"包裹弹性"就越高,也就是说,封装性越好,对代码的更改所造成的影响就越低.2. non-m...
阅读全文
摘要:1. 设计类时,应该将成员变量声明为private,尽量避免用户对成员变量的直接访问,使用户只能通过函数接口访问成员,这样利于实现封装,特别是当类需要改变(添加或减少成员变量)时,只需要改变接口实现,对于用户来说只需要重新编译即可(否则类的用户需要修改大量对成员变量进行访问的代码)2. protec...
阅读全文
摘要:1. 虽然一般情况下传参使用const-by-reference-to-const比较好,但返回值有时必须是对象而不是引用: 当reference绑定到函数内创建的局部对象时,函数调用结束后引用绑定在一个不存在的对象; 当reference绑定到堆内存对象时,函数调用后比较容易忽略内存释放,特别...
阅读全文
摘要:1. 以reference-to-const传递参数的优点: 避免局部对象的构造和析构,节省时间和空间; 避免参数派生类对象向基类对象传递时的"对象切割",实现面向对象;2. reference虽然是"别名",但是底层实现往往是指针,因此对于内置类型,选用pass-by-value效率更高.这也...
阅读全文
摘要:1. 设计优秀的class是一项艰巨的任务,因为设计好的types是一项艰巨的工作,好的types有自然的语法,直观的语义,以及一个或多个高效实现品.2. 要设计一个良好的class,需要思考以下问题: 1). 新types对象应该如何被创建和销毁? 涉及到构造函数,析构函数,内存分配和释放...
阅读全文
摘要:1. 好的借口很容易被正确使用,不易被误用.2. "促进正确使用"的方法包括借口的一致性(例如STL容器用于统计大小的函数都名为size)以及与内置类型的行为兼容(例如重载*返回的值应加const限定以防被篡改).3. 阻止误用的办法包括建立新类型,限制类型上的操作,束缚对象值(使用枚举,stati...
阅读全文
摘要:1. 有些智能指针类(比如shared_ptr)不支持隐式类型转换,假设存在这样两个函数:void fun(shared_ptr lhs,int rhs);int foo();View Code那么对于以下函数调用:fun(new int,foo());将不能通过编译,解决方法之一:fun(shar...
阅读全文
摘要:(参考自 http://www.cnblogs.com/hazir/p/new_and_delete.html)1. new和delete不是函数,是C++的关键字.2. new一个对象的实际操作分为两步:1). 调用标准库函数operator new分配内存 2)调用构造函数初始化(如果new的是...
阅读全文
摘要:1. 有时资源管理类(resource-managing classes)需要提供对资源的直接访问,这就需要将RAII class对象转换为其内含的原始资源,有两种做法可以达成目标:显式转换和隐式转换.2. 显式转换:shared_ptr和auto_ptr都提供一个get成员函数,用来执行显式转换,...
阅读全文
摘要:1. 条款13导入RAII的观念:资源获取时机便是初始化时机,资源会在不需要的时刻被销毁,典型代表就是shared_ptr和weak_ptr,但是并非所有资源都是堆内存,例如外存和堆栈,在这种情况下,auto_ptr,shared_ptr,weak_ptr显然不适合作为资源管理类,这就需要建立自己的...
阅读全文
摘要:1. 在使用堆内存时,需要手动delete指针以防内存泄露,但是有些例外情况(例如发生异常)会使得内存资源无法释放,此外,使用者也极有可能忘记释放堆内存,因此需要"以对象管理资源",也就是把资源放进对象内,用析构函数来确保资源被释放,这种思想被称为"资源取得时机就是初始化时机"(Resource A...
阅读全文
摘要:1. 编译器合成的拷贝构造函数默认调用基类的拷贝构造函数,合成的拷贝构造操作符也是一样.2. 对于自己编写的拷贝构造函数,编译器不再默认调用基类的拷贝构造函数,仅在拷贝构造函数中没有初始化基类部分时调用默认构造函数.对于自己编写的拷贝赋值操作符,编译器不额外作任何操作(即使类的编写者忘记调用基类的拷...
阅读全文
摘要:1. 为了支持形如“a=b=c”的连锁形式,最好令operator=返回一个reference to *this.2. 如果类中含有用于指向堆内存的指针,那么赋值操作符就要注意自我赋值的问题,例如:class A{public: ... A& operator=(const A& tmp...
阅读全文
摘要:1. 在一个继承体系中,最底层的派生类在构造过程中,先初始化基类部分,再按继承层次依次初始化派生类部分,因此被构造的对象先作为一个基类对象,再按继承层次依次成为派生类对象,例如,在继承层次A→B→C→D中,构造一个D类对象,其依次经历了A→B→C→D的转变,因此对于以下代码:#include usi...
阅读全文
摘要:1. 当异常发生时,如果异常发生在一个try块内部,程序就会跳出该try块,并逐层寻找匹配的catch,跳出try块的过程中,会销毁该try内创建的对象并调用析构函数,如果调用析构函数的过程中又发生异常,程序就会调用标准库terminate函数(terminate函数调用abort函数)结束执行,例...
阅读全文
摘要:1. 左值与右值: C++对于左值和右值没有标准定义,但是有一个被广泛认同的说法:可以取地址的,有名字的,非临时的就是左值;不能取地址的,没有名字的,临时的就是右值. 可见立即数,函数返回的值等都是右值;而非匿名对象(包括变量),函数返回的引用,const对象等都是左值. 从本质上理解,创建和销毁由
阅读全文
摘要:1. 成员函数只有被需要(被调用)才必须有定义,同理,只有当默认构造函数,拷贝构造函数,赋值操作符,析构函数被需要而类定义它们时,它们才会被编译器创建出来(除非函数在基类中被声明为虚函数,编译器产生的函数是非虚的,public的).2. 并不是只要类没有定义默认构造函数,拷贝构造函数,赋值操作符时编...
阅读全文
摘要:(参考自《深入理解C++对象模型》)”C++新手一般有两个常见的误解:任何class如果没有定义default constructor,就会被合成一个出来.编译器合成出来的default constructor会明确设定class 内每一个data member的默认值.”现在主要解释第一条为什么是...
阅读全文
摘要:1. 如果一个类将要作为基类,那么它应该具有一个虚析构函数以防止delete经由基类指针指向的派生类对象时发生的"局部销毁"问题,避免造成内存泄露,数据结构败坏,在调试器上浪费时间等问题;任何带有虚函数的类几乎肯定需要一个虚析构函数.2. 在不必需的情况下不应该将成员函数设为虚函数,否则,如果导致一...
阅读全文
摘要:1. 某些类的含义决定了它们不具备某些功能,也就是说某些函数不能被创造出来以防被错误的使用(例如定义一个Book类,它含有一个表示ISBN的变量,这种情况下拷贝构造函数以及赋值操作符显然是没有意义的,因为任何两种书的ISBN都不同),但是编译器在类的创建者没有声明默认构造函数,拷贝构造函数,赋值操作...
阅读全文
摘要:1. 对于内置类型,如果变量在全局作用域内定义,默认初始化为0,如果变量在局部作用域内定义,默认不进行初始化;对于类类型,默认调用默认构造函数进行初始化,如果没有默认构造函数,则必须显式初始化.2. 构造函数对成员进行初始化的动作发生在初始化列表中而不是函数体内,在函数体内进行的"初始化"实际上是赋...
阅读全文
摘要:1. const可被施加于任何作用域内的对象,函数参数,函数返回类型,成员函数本体.用const修饰指针,如果const出现在*之前,表明指针不能更改所指向的对象的内容,如果const出现在*之后,表明指针只能指向同一块内存.另外int const*p和const int*p含义相同.如果对象成员有...
阅读全文
摘要:1. 有些情况下,宁可以编译器替换预处理器,因为#define并不被视为语言的一部分从而导致某些问题.2. 不带参数的宏展开引起的符号"丢失"问题. 例如,对于"#define ASPECT_RATIO 1.635",编译器在处理源代码之前ASPECT_RATIO就已经被替换为1.635,于是记号名...
阅读全文
摘要:1.一开始,C++只是C加上一些面向对象特性,最初名称为"C with Classes"(带类的C).2.如今的C++已经是个多重泛型编程语言,同时支持过程形式(procedural),面向对象形式(object-oriented),函数形式(functional),泛型形式(generic),元编...
阅读全文