More effective C++读书笔记

条款13 抛出一个异常和函数调用之间的区别

  • 在抛出异常时,异常对象总是会被复制,无论抛出的是一个指针、对象还是引用。抛出的是指针时,将复制这个指针的内容(仅仅是地址,而不是对象,类似于浅拷贝),注意千万不要抛出局部对象的指针,不然外部捕获的将是一个悬垂的对象;抛出引用时,将以引用的静态类型(而不是动态类型)为蓝本进行复制;抛出一个对象时,还是会复制一个该对象,如果在捕获函数对象的时候,使用值传递的方式,甚至会复制2次。
  • 捕获异常的时候,允许的转换动作要少一些。只允许2种形式:1.异常继承体系中的类转换。2.有型指针转换为void*指针的转换。
  • 多个catch语句时,匹配采用的是first fit策略。虚函数则采用的是best fit策略。
    读者认为,这里要将抛出异常和捕获异常的过程,分开来看。

效率

条款16 80-20 法则

  • 一个程序80%的时间花费在20%的代码上,80% 的内存被20%的代码使用。80% 的磁盘访问动作由20%的代码执行,80%的维护力气花费在20%的代码上。
  • 程序性能特质倾向高度的非直觉性,应该借助程序分析器profiler来优化代码。

条款 17 缓式评估lazy evaluation

  • 也就是拖延战术。直到万不得已的时候才真正做最要紧的事。
  • 1.引用计数和数据共享
string s1 = "hello";
string s2 = s1;	//这时s2没有自己的私有数据,而是共享s1的数据
cout << s1;
cout << s1 + s2;	//这时因为是读操作,s2还是没有自己的私有数据,仍旧是共享s1的数据

s2.upper();//将s2的小写转为大写,编译器在此之前,才会将s2构造出私有数据,因为不得不构造一份数据了
  • 2.区分读和写。运用缓式评估和proxy classes,可以区分效率成本不同的读和写。
string s = "hello world!";
cout << s[1];		//读操作
s[2] = 'd';			//写操作
  • 3.缓式取出。当存取一个大型的对象时,而只使用某些字段时:我们构造一个外壳,只需要在真正使用这些字段时,才进行存取这些需要的字段。当然这会造成额外的代码负担。
  • 4.表达式缓评估。

条款18 分摊计算时的成本到计算之前

此条款的含义是超急评估over eager evaluation, 尽早的提前做事。典型的以空间换取时间的做法。

  • 1.缓存 caching。
  • 2.预取出 prefetching。

条款19 了解临时对象的来源

函数中具有明确名字的对象叫局部对象,C++中真正的临时对象是不可见的,这些临时对象。
主要有2种情况发生:

  • 当隐式类型转换发生的时候。
  • 函数返回对象的时候。

任何时候,只要看到reference-to-const的函数参数,就十分有可能产生一个临时对象。任何时候当你看到函数返回对象的时候,也会产生临时对象。

条款20 协助完成“具名返回值优化NRVO” name return value optimization

  • 函数需要返回对象的时候,不要返回内部对象的指针和引用。指针需要手动去释放内存,而内部对象的引用对象会在函数体结束被销毁。
  • 最优效率的写法:(会触发具名返回值优化)
inline const Rational operator*(const Rational& lhs, const Rational & rhs){
	return Rational(lhs.numerator() * rhs.numerator(), lhs.denominator() * rhs.denominator());
}
  • 具名返回值优化需要这个类具有copy constructor 函数,因为本优化就是为了 消除copy constructor的函数调用的问题。
  • 具名返回值优化的副作用是copy constructor函数的代码不会被执行。

条款21 利用重载技术避免隐式转换

隐式转换时候,很方便程序员写代码。但是隐式转换会导致产生一个临时对象,影响效率。
比较好的方法时,对于可能的隐式转换都定制重载函数。

class UPInt{
public:
	UPInt();
	UPInt(int);
};

const UPInt operator+(const UPInt& lhs, const UPInt& rhs);

UPInt upi1, upi2;
UPInt upi3 = upi1 + upi2;

upi3 = 1 + upi1;//这里会进行隐式转换
upi3 = upi2 + 1;//这里会进行隐式转换

修改如下:

const UPInt operator+(const UPInt& lhs, int rhs);
const UPInt operator+(int lhs, const UPInt& rhs);

UPInt upi1, upi2;
UPInt upi3 = upi1 + upi2;

upi3 = 1 + upi1;//这里不会进行隐式转换
upi3 = upi2 + 1;//这里不会进行隐式转换
  • C++规定,每一个重载操作符必须获得至少一个“用户定制类型”的自变量。

条款22 考虑以操作符的复合形式op=来取代独身形式(op)

最好以 operator+= 和operator-=来实现 operator+ 和 operator-,并让函数可以执行返回值优化NRV。

class Rational{
public:
	Rational& operator +=(const Rational&rhs);//并已实现
	Rational& operator -=(const Rational&rhs);//并已实现
};
//且只需要维护-=,+=等就可以了。
const Rational operator+(const Rational& lhs, const Rational& rhs){
	return Rational(lhs) += rhs;	//这样写可以实现NRV
}

const Rational operator-(const Rational& lhs, const Rational& rhs){
	return Rational(lhs) -= rhs;	//这样写可以实现NRV
}
  • 匿名对象更容易被消除。

条款23 考虑使用不同的程序库

不同的程序库在性能以及效率、实现方式、适用性均有不同表现,选择合适的程序库来契合不同的场景。

条款24 了解virtual functions、multiple inheritance、virtual base classes、runtime type identification成本

条款25

条款26 限制某个类可能产生的对象

不允许对象产生

将constructor设置为private 或者设置为delete。

class CantBeInstantiated{
private:
	CantBeInstantiated();
	CantBeInstantiated(const CantBeInstantiated&);
}
或者
class CantBeInstantiated{
public:
	CantBeInstantiated() = delete;
	CantBeInstantiated(const CantBeInstantiated&) = delete;
}

只允许一个对象产生(单例模式)

  • 使用单例模式,即scott meyers模式。(注意不要对有单例模式的函数使用inline,会导致严重问题,inline实际上是要求该函数被调用时,使用inline函数体来替换调用函数,会导致代码复制,static静态对象也会被复制,从而导致出现多个对象,违背预期;同时也导致代码量上升。)
class A{
public:
	void func();
	friend Printer& thePrinter();
private:
	Printer();
	Printer(const Printer* lhs);
}
Printer& thePrinter(){
	static Printer p;
	return p;
}
  • 通过类中的静态变量来限制数量,当请求的对象个数太多是跑出异常。
class Printer{
public:
	class TooManyObject{};
	Printer();
	~Printer();
private:
	static size_t numObject;
	Printer(const Printer& rhs);
};

size_t Printer::numObject = 1;
Printer::Printer(){
	if(numObject >= 1){
		throw TooManyObject;
	}
	
	//其他操作
	numObject++;
}
Printer::~Printer(){
	//析构对象
	--numObject;
}

允许多个对象产生

使用类模板,通过类模板的静态变量来控制对象产生。

读书记录

2022.4.27 条款13

2022.4.28 条款16,17

2022.4.29 条款18

2022.4.30 条款19,20

2022.5.6 条款21,22,23,24

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值