【Effective C++读书笔记】篇八(条款18~条款21)

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


请记住:

1、好的接口很容易被正确使用,不易被误用。你应该在你的所有接口中努力达成这些性质;

2、“促进正确使用”的办法包括接口的一致性,以及与内置类型的行为兼容;

3、“阻止误用”的办法包括建立新类型、限制类型上的操作,束缚对象值,以及消除客户的资源管理责任;

4、tr1::shared_ptr 支持定制删除器。这可防范 DLL 问题,可被用来自动解除互斥锁等等。





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


请记住:Class 的设计就是 type 的设计。在定义一个新的 type 之前,请确定你已经考虑过本条款覆盖的所有讨论主题。





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


pass-by-value 除了会有重新构造的代价外,还存在对象切割的问题。即当一个 derived 对象以 by value 方式传递给 base 对象时,会被视为一个 base 对象, derived 的构造函数并不会被调用,被调用的是 base 的构造函数。

举例如下:

<span style="font-size:14px;">#include <iostream>
using namespace std;

class base
{
	public:
		base(){cout << "base()" << endl;}
		base(const base& b){cout << "copy base()" << endl;}
		~base(){cout << "~base()" << endl;}
};

class derived: public base
{
	public:
		derived(){cout << "derived()" << endl;}
		derived(const derived& d){cout << "copy derived()" << endl;}
		~derived(){cout << "~derived()" << endl;}
};

void fun(base b)
{
	return;
}

int main()
{
	derived d;
	fun(d);
	return 0;
}</span>

结果如下:

<span style="font-size:14px;">base()
derived()
copy base()
~base()
~derived()
~base()
</span>


当改为 pass-by-reference-to-const 方式时,就不会存在这个问题,因为 reference 往往以指针实现。


这里有个小插曲,为什么拷贝构造函数入参是 pass-by-reference-to-const?

如果是 pass-by-value 的话,由于 pass-by-value 本身的入参方式就需要调用拷贝构造函数,于是会陷入无穷的递归当中,这是编译器所不允许的。


请记住:

1、尽量以 pass-by-reference-to-const 替换 pass-by-value。前者通常比较高效,并且可避免切割问题(slicing problem)。

2、以上规则并不适用于内置类型,以及 STL 的迭代器和函数对象。对它们而言,pass-by-value 往往比较适当。





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


对于一个函数,如果其必须返回对象时,别妄想返回其引用,这里我们可以简单分析一下返回 reference 的后果:

1、对于 stack based 变量:

base& fun()
{
    base tmp;
    return tmp;
}
返回的结果在函数退出前就被销毁了,返回值如今已是一个败坏的残骸。


2、对于 heap based 变量:

base& fun()
{
    base *pb = new base;
    return *pb;
}
分配在堆区的变量,试问谁来对其进行 delete 操作?很容造成内存泄露。


3、以上两种使用方式非常不好,有人于是想出“让 operator* 返回的 reference 指向一个被定义在函数内部的 static base 对象 ”:

const base& operator*(const base& b1, const base& b2)
{
    static base result;
    result = ...;
    return result;  
}
对于 static 对象,其不可避免的遭受多线程安全性的怀疑,不过在那之前,还有更容易被忽视的安全性:

bool operator==(const base& b1, const base& b2){};     // 一个针对 base 而写的 operator==
base b1, b2, b3, b4;
...
if((b1 * b2) == (b3 * b4))
{...}
else
{...}
在你执行之后会发现,此代码永远执行是 true 分支。那是因为 operator*  函数里的 static 对象只有一个,operator* 后所有对象是该对象的引用,导致operator== 执行的其实是 (static 对象 == static 对象) 的操作。 

请记住:绝对不要返回 pointer 或 reference 指向一个 local stack 对象,或返回 reference 指向一个 heap-allocated 对象,或返回 pointer 或 reference 指向一个 local static 对象而有可能同时需要多个这样的对象。



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值