Effective C++阅读笔记




整本书,我只想写一篇博客,只注重概要,例子不会太多,主要是说思想,短小精悍是最好的。

这本书以前读过,只是觉得当时看得不仔细,现在想回头再看看这个东西。

1.让自己习惯c++

        这一部分算是c++的一个导读吧,可以作为一个引子,其实并没有涉及什么c++的技术细节,只是给了概览性的一个叙述,在这里还不需要深厚的c++功底。

条款01:视C++为一个语言联邦

        c++是c plus plus的一个简写,望文生义的来说的话,它是比C多了些东西。除了面向过程,它还能面向对象,当然了,面向对象之前还有基于对象的方式;此外,它还支持函数形式,泛型和元编程。

        泛型是一种思想,它的实现可以参照STL,里面的容器,算法,迭代器和函数对象(也即functor)等机制。boost也是不可忽略的一个庞大的库,对于C++11的主要来源,11里的24个新特性从boost里获取了15个,它的重要性可见一斑。在看STL源码解析的时候,觉得STL很大程度上解决了编程时的通用代码的编写,主要是里面的容器和算法,但是有时候还需要自己写点儿数据结构和算法的东西;但接触了boost之后,虽然没有完全的不用自己再写东西,但是里面的smart_ptr,bind和function,multi-index和hash等等确实比STL更加方便了,boost是完全和STL兼容的。


条款02:用const,enum和inline替换#define

        宁可以编译器替换预处理器比较好。开篇就看到这句话了,define的东西是在预处理阶段进行替换的,在程序的编译阶段,这些东西已经没了踪影。若是改用const等,从编译到实际的调试过程中,都可以看到这些名称。这里有两个例外情况:

        第一,定义常量指针:有两个地方可以写const,分别是*之前和之后,之前的是对指向的const,之后是对指针自身。

        第二,class专属的常量,最好是弄成static的,避免一个每个实例都有一份。g++的稍高一点儿的版本貌似都支持基本类型在声明时直接赋值了。static的东西,若是不赋初值,默认为0;

        enum更像define,不能取址,只能取值。它还是tmp的基础技术,等了解了template metaprogramming技术了再更好的理解它吧,目前只能就它在C里的用法来了。

        inline和define都能定义函数,但是inline更oo一些,而且不用再去考虑括号是否漏掉了一个等等等。

        这里就出来了一个规则了,对于:

        简单常量,const或enum更好,enum更适合有多重取值的情况;

       对于小函数,inline就是绝配了。


条款03:尽量使用const

这个条款没什么可说的觉得,只是在你需要恒定不变的地方加上const,可以是在类,namespace,operator,指针,迭代器,reference,和函数以及局部和全局的变量等等。

两个函数,如果只是constness不同,是可以被重载的。constness就是函数末尾写的那个const。比如一个operator[],当是constness的时候,它可以用于const对象;但是constness的[]不能做左值,你懂的。

当我们声明一个函数为const的时候,默认它是bitwise constness,这样如果有个char *p成员变量,它指向一个buffer,虽然[]为constness,但是如果用一个char*去指向p,之后对p的任何修改都是符合bitwise constness的,这是因为指针而非所指物是成员。这种情况即所谓的logical constness。那么编译器坚持bitwise constness的情况下,如果有成员表示p的大小,在一个const 函数中,是不允许修改这样的变量的,可以用mutable做个修饰,释放掉non-static成员变量的bitwise constness的约束。

在constness和non-constness中避免重复:如果一个同名、同参数的函数,只是constness不一样,其它要做的事情完全相同,只是返回值的constness的差别;但是我们还要有两份完全一样的函数体,代码是重复的,耗费了双倍的编译时间,代码体积也进而膨胀,可以考虑使用转型(casting),从non-const函数或operator里调用const version,在调用之前和之后都要做下const转换。为什么不用const调用non-const呢?那个const是不能改动对象的,除了mutable的,但是你却可能在non-const时改动对象的内容。

注意:

1.将sth声明为const可以帮助编译器侦测出错误用法。const可以用于前述的一对东西。

2.编译器认为的是bitwise constness,但是程序员应该使用的却是conceptual constness。

3.当一个成员函数或operator有两个const和non-const两个版本时,用non-const调const版本可以避免代码重复;但是反之会引入const版本里改动对象内容的风险。


条款04:确定对象在使用前已被初始化

永远在使用对象之前将其初始化。

1.对于语言内置类型,要手工完成。

2.内置类型之外的东西,初始化发生在构造函数身上。

构造函数的调用分两步:

第一步是初始化,即对参数列表,构造函数后面加个冒号的那个东东;

第二部是赋值,发生在构造函数体内;

所以,对非内置类型,初始化的时候会调用默认constructor,要是写在构造函数体内,就会调默认构造和copy assignment operator,所以初始化列表的方式是最好的,只调copy constructor。对内置类型,写到哪儿倒是都一样,初始化和赋值的成本无异,不过为了和非内置统一,都初始化列表吧。

要分得清楚什么是拷贝构造和拷贝复制操作符,这两个概念在essential cpp里面就讲过了,不再赘述哈。见谅。

构造函数初始化变量的顺序,和构造函数的参数列表的顺序无关,但和定义类时写的参数的顺序有关,为了统一,最好保持二者的一致性。

如果成员变量是const或reference,则必须初始化,不能够被赋值。

不同编译单元之间不要使用对方的non-local static 对象,因为被使用的对象可能未初始化,C++对不同编译单元之间的non-local static对象的初始化顺序没有明确定义。为避免在对象初始化之前过早的使用他们,需要做到:

第一、手工初始化内置型non-member对象。

第二、使用成员初始化列表对付对象的所有成分。

最后,基于non-local static的初始化次序不确定来进行设计。

注意:

1、为内置型对象手工初始化,因为C++不保证初始化它们。

2、构造函数最好使用memeber initialization list,而不要再constructor内使用assignment。初值列列出的成员变量,其排列次序应该和它们在class中的声明次序相同。

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


2.构造、析构、赋值运算

条款05:了解C++默默编写并调用哪些函数

当你写了一个空的class的时候,编译器会默认为你构造四个函数或operator:默认构造函数,拷贝构造函数,析构函数和copy assignment operator。

但当你写了一个带实参的构造函数时,编译器将不会为你自动添加默认构造函数。


条款06:若不想使用编译器自动生成的函数,就该明确拒绝

若是不想一个类的对象被拷贝,就把它的copy constructor和copy assignment operator声明为private,并且不予实现,这样当出现拷贝行为时会报错;

若是在该类的成员函数或者是friend的东西里调到他时,也会报错,但是是在链接时,要想把错误移到编译时,可以继承自一个父类,把着两个设为private,并且是private继承。典型的这种父类即boost::noncopyable。

继承是否非要是private才可以嗯,明天试一下再添加进来


条款07:为多态基类声明virtual destructor

条款08:别让异常逃离destructor

条款09:绝不在构造和析构过程中调用virtual函数

条款10:令operator=返回一个reference to *this

条款11:在operator=中处理"自我赋值"

条款12:复制对象时勿忘其每一个成分

3资源管理

条款13:以对象管理资源

条款14:在资源管理类中小心coping行为

条款15:在资源管理类中提供对原始资源的访问

条款16:成对使用new和delete时要采取相同的形式

条款17:以独立语句将newd对象置入智能指针

4设计与声明

条款18:让接口容易被正确使用,不易被误用

条款19:设计class犹如设计type

条款20:宁以pass by reference to const替换pass by value

条款21:必须返回对象时,别妄想返回其reference

条款22:将成员变量声明为private

条款23:宁以non-member、non-friend替换member函数

条款24:若所有参数皆需类型转换,请为此采用non-member函数

条款25:考虑写出一个不抛异常的swap函数

5实现

条款26:尽可能延后变量定义式的出现时间

条款27:尽量少做转型动作

条款28:避免返回handles指向对象内部成分

条款29:为"异常安全"而努力是值得的

条款30:彻底了解inlining的里里外外

条款31:将文件间的编译依存关系降至最低

6继承与面向对象设计

条款32:确定你的public继承塑模出is-a关系

条款33:避免遮掩继承而来的名称

条款34:区分接口继承和实现继承

条款35:考虑virtual函数以外的其他选择

条款36:绝不重新定义继承而来的non-virtual函数

条款37:绝不重新定义继承而来的缺省参数值

条款38:通过复合塑模出has-a或"根据某物实现出"

条款39:明智而审慎地使用多重继承

7模板与泛型编程

条款41:了解隐式接口和编译期多态

条款42:了解typename的双重意义

条款43:学习处理模板化基类内的名称

条款44:将与参数无关的代码抽离templates

条款45:运用成员函数模板接收所有兼容类型

条款46:需要定义类型转换时请为模板定义非成员函数

条款47:请使用traits classes表现类型信息

条款48:认识template元编程

8定制new和delete

条款49:了解new-handler的行为

条款50:了解new和delete的合理替换时机

条款51:编写new和delete时需固守常规

条款52:写了placement new,也要写placement delete

9杂项讨论

条款53:不要轻忽编译期的警告

条款54:让自己熟悉包括TR1在内的标准程序库

条款55:让自己熟悉Boost

to be continued



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值