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

声明:

  1. 文中内容收集整理自《Effective C++(中文版)第三版》,版权归原书所有。
  2. 本内容在作者现有能力的基础上有所删减,另加入部分作者自己的理解,有纰漏之处敬请指正。

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

Make interfaces easy to use correctly and hard to use incorrectly.

直接进入正题。

一个一般性准则“让types容易被正确使用,不容易被误用”的表现形式:“尽量令你的types的行为与内置types一致”。例如客户已经知道int这样的type有什么行为,所以你应该努力让你的types也有相同的表现。这种“一致性”更能导致“接口容易被正确使用”。

任何接口,如果要求客户必须记得做某些事情,就是有着“不正确使用”的倾向,因为客户可能会忘记做那些事情。例如条款13导入了一个factory函数,它返回一个指针指向Investment集成体系内的一个动态分配的对象:

Investment* createInvestment();

为了避免资源泄漏,createInvestment返回的指针最终必须被删除,但那至少开启了两个客户犯错的机会:没有删除指针或者同一个指针删除了两次。

条款13表明客户如何将createInvestment的返回值存储于一个智能指针中,从而将delete责任推给智能指针。但万一客户忘记使用智能指针怎么办?很多时候,较佳的接口设计原则是先发制人,就令factory函数返回一个智能指针:

std::tr1::shared_ptr<Investment createInvestment();

这便实质上强迫用户将返回值存储于一个tr1::shared_ptr内,几乎消除了忘记删除底部Investment对象的可能性。实际上,返回tr1::shared_ptr让接口设计者得以阻止一大群客户犯下资源泄漏的错误。

假设class设计者期许那些“从createInvestment取得Investment指针”的客户将该指针传递给一个释放资源的函数(如getRidofInvestment),而不是直接在它身上动刀(即使用delete),这样就有着“不正确使用”的倾向了,该“不正确行为”是“企图使用错误的资源析构机制”。

该函数的设计者可以先发制人:返回一个将getRidofInvestment绑定为删除器的tr1::shared_ptr

tr1::shared_ptr提供的某个构造函数接收两个实参:一个是被管理的指针,另一个是引用次数变成0时将被调用的“删除器”。这样我们就可以创建一个null tr1::shared_ptr并以getRidofInvestment作为其删除器。

注意tr1::shared_ptr构造函数的第一个参数必定是个指针,因此如果想要建立null shared_ptr,不能使用数字0,而需要显示转换其为指针:static_catst<classType*>(0)。 

std::shared_ptr<Investment> pInv(static_cast<Investment*>(0), getRidofInvestment);

如果不把pInv初始化为null然后再对其进行赋值,而是将原始指针直接传递给pInv构造函数会更好。

代码看起来就像这样:

std::tr1::shared_ptr<Investment> createInvestment()
{
	std::tr1::shared_ptr<Investment> retVal(static_cast<Investment*>(0), getRidofInvestment);
	retVal = ...; //令retVal指向正确的对象
	return retVal;
}

tr1::shared_ptr的另一个特别好的性质是:它会自动使用它的“每个指针专属的删除器”,因而消除另一个潜在的客户错误:所谓的“cross DLL problem”。这个问题发生于“对象在动态连接程序库中被new创建,却在另一个DLL内被delete销毁”。在许多平台上,这一类“跨DLL的new/delete成对运用”会导致运行期错误,tr1::shared_ptr没有这个问题,因为它缺省的删除器是来自“tr1::shared_ptr诞生所在的那个DLL”的delete。

请记住:

  1. 好的接口容易被正确使用,不容易被误用。
  2. 促进正确使用的办法包括接口的一致性,以及与内置类型的行为兼容。
  3. 阻止误用的办法包括建立新类型、限制类型上的操作,束缚对象值,以及消除客户的资源管理责任。
  4. 多多使用shared_ptr来代替原始指针。shared_ptr支持定制型删除器。这可预防DLL问题,可被用来自动解除互斥锁(见条款14)。

猜你喜欢

转载自blog.csdn.net/longmenshenhua/article/details/88796365