最近瞻仰了一下Scott Meyers久负盛名的《effective c++》,特来总结一下,以加深一下印象与防止自己今后记忆力衰退。这本书里很多都是工程上很有意思的tips,也让我重新增加了对cpp的喜爱,真希望有机会好好写写cpp的工程。

零、前言

声明 告诉名称和类型
定义 为对象分拨内存,为函数或函数模版提供代码体,对类和类模版列出它们成员
初始化 给予对象初值
显示构造函数更受欢迎,除非有很好理由隐式转换
Typename variable = sameTypeVariable 也是调用拷贝构造函数
函数对象 行为像函数的对象 来自于重载了operator()的classes
TR1 和 Boost

一、让自己习惯cpp

1 cpp是个多重范型编程语言 支持过程形式,面向对象形式,函数形式,泛型形式,元编程形式
cpp是个语言联邦  c。Obj-oriented。template。STL。
2 尽量以const,enum,inline替换#define
class中static整数常量不取地址,编译器不要求可以只声明不定义,否则必须提供额外定义式。声明时可获得初值(除非是旧编译器)。
编译器必须在编译期间知道数组大小,万一不允许static整数型class常数的in class 初值设定,可用enum hack
Enum {num = 5}
更像define不会导致非必要内存分配。
Enum hack是模版元编程的基础。
用inline代替宏
3 尽可能使用const
Const iterator 是常数指针 const_iterator是指向常数的指针
成员函数只是常量性不同可重载
Bitwise const 成员函数不更改任何成员变量,实际上对顶层const指针所指对象无效。Logical const 可以修改客户端侦测不到的bits,即承诺不改变逻辑状态。编译器强制bitwise,但我们写的是概念上常量。
用non-const函数调用const函数
Const_cast<char&>(static_cast<const xxx>(*this)[position])
4 确定对象使用前已经初始化
成员初始化发生在进入构造器之前,用初值列表代替赋值。
不同编译单元内定义的non-local static对象的初始化次序无明确定义。函数内的被称为local static。可以用singleton模式可以解决这个问题,用函数调用来取这些对象的引用。即用local static 替换 non-local static
Implicit template instansiations

二、构造,析构,赋值运算

5 cpp默默编写了哪些函数,默认构造,拷贝构造,析构,赋值。都是public inline。
对于一些难题,编译器选择拒绝生成默认拷贝构造函数。(引用,基类赋值操作为私有)
6 不想编译器自动生成的函数,明确拒绝,声明private,不去定义。
7 多态基类声明virtual析构函数
不当基类的话就不要virtual了,增加内存还使得对象和其他语言的结构不同。
每个带有virtual函数的class都有一个相应的vtbl虚函数表,由函数指针组成的数组。当对象调用一个virtual函数实际调用的函数取决于该对象的vptr虚函数表指针所指的那个vtbl,编译器在其中寻找适当的函数指针。
8 异常不出析构函数
两个异常同时存在
把关闭的责任从析构函数转移到客户手上,如果客户不管,退回到析构函数强迫结束程序或吞下异常。
原因:数组中元素析构异常阻碍其他元素析构
9 不在构造,析构过程中调用virtual函数
在构造期间,virtual函数不是virtual的。在派生类的基类构造期间,对象类型还是基类,不是派生类。
构造期间可以借由派生类将必要构造信息向上传递到base构造函数替代向下调用virtual函数。
10 令operator=返回一个reference to *this
这个协议被任何内置类型与标准库类型遵守
11 Operator=中处理自我赋值,加入证同测试。
用复制构造函数达到异常安全和自我赋值安全。另一个常见够好的技术是copy and swap
type & operator=(const type& rhs) {
type temp(rhs);
swap(temp);
return *this;
}
void swap(type &rhs);
先记住原先资源,创建副本,删除原先资源。
12 复制对象时勿忘每个成分
让派生类的copying函数调用相应的基类函数
不要用copying函数实现另一个copying函数,将共同机能放进另外一个函数

三、资源管理

13 以对象管理资源,RAII
Auto_ptr智能指针,其析构函数自动对其对象调用delete
获得资源以后立即放入对象管理。
若通过copy复制auto_ptr只有复制所得的指针取得资源唯一所有权,预防重复删除。
stl容器容不得auto_ptr,因为要求其元素正常发挥复制行为。
引用计数型智慧指针RCSP,shared_ptr,持续追踪多少对象指向某资源
它们析构函数用的是delete,所以数组暂时不好。可以看看boost。
14 在资源管理类中小心copy行为
当RAII对象被复制?
禁止复制
对底层资源使用引用计数法(使用shared_ptr,指定删除器)
复制底部资源,深度拷贝
转移底部资源的拥有权
15 在资源管理类中提供对原始资源的访问
提供get成员函数返回原始指针的复件
16 成对使用new和delete时要采用相同形式
小心对数组的typedef行为
17以独立语句将newed对象放入智能指针
资源被创建和资源被转换为资源管理对象两个时间点之间有可能发生异常干扰。
比如因为函数调用中的参数运算次序不一定性可能异常。

五、实现

透彻了解inlining,免除函数调用成本,编译器优化机制通常被设计浓缩那些不含函数调用的代码。
代价:增加目标码大小,即使拥有虚拟内存,inline造成的代码膨胀也会导致换页(paging)行为,降低指令告诉缓存装置的击中率,以及伴随这些而来的效率损失。重新编译的代价。
inline函数通常一定被置于头文件,inlining大多是编译期行为。
templates也通常被放在头文件。不要因此就声明为inline
出现函数指针指向inline函数依旧会有个函数本体,函数指针调用不会inlined,函数名调用可能通过编译器认可会inlined
将大多数inlining限制在小型、频繁调用的函数上。可使日后的调试过程和二进制升级更容易,也可使潜在的代码膨胀问题最小化,使程序的速度提升机会最大化。

《深度探索c++对象模型》

一、关于对象

1 C++对象模型
每一个non-inline member function只会诞生一个函数实例。
C++布局存取时间上主要的额外负担来自virtual,virtual function用以支持一个有效率的“执行期绑定“
virtual base class 用以实现”多次出现在继承体系中的base class,有一个单一而被共享的实例。
多重继承下的额外负担发生在一个派生类和它的第二或后继的基类转换。
Nonstatic data members 在对象内
static data members 在对象外
static and nonstatic function members 在对象外
virtual function
1、每一个class产生出一堆指向virtual functions的指针,放在表格中,被称为virtual table(vtbl)
2、每一个class object被安插一个指针,指向相关的virtual table。通常这个指针被称为vptr。vptr的设定和重置都由每一个class的constructor、destructor和copy assignment运算符自动完成。每一个class所关联的 type_info object(用以支持runtime type identification, RTTI)也由vtbl被指出来,通常放在表格的第一个slot。

「Unity Shaders」Surface Shaders and Texture Mapping

 本文内容参考《Unity 5.x Shaders and Effects Cookbook》 表面着色器和材质贴图 总的来说,一个表面着色器有两个关键的步骤。第一,必须确定材质的物理...

阅读全文

「Unity Shaders」Creating First Shader

创建第一个着色器 最近学习了一段时间Unity Shader相关知识,在进一步自顶向下学习计算机图形学之前,先将之前看《Unity 5.x Shaders and Effects Cookbook...

阅读全文

网易互娱2017实习生招聘在线笔试第一场

本周五参加了网易互娱2017实习生招聘在线笔试第一场(难倒还有好几场),题目总体上比较基础,一读题就有思路,不过手速快才能写完。 比赛链接 题目1 : ...

阅读全文

1 条评论

欢迎留言