第15+1条: 互相联系的 new 和 delete 要使用同样的形式
第2条: 要在单独的语句中使用智能指针来存储由 new 创建的对象
第3条: 要让接口易于正确使用,而不易被误用
l 保持与内置数据类型有一致的行为,是使接口易于正确使用的一种可行的方法。
l 防止错误发生的方法有:创建新的数据类型,严格限定类型的操作,约束对象的值,不要将管理资源的任务留给客户端程序员。
l tr1::shared_ptr 支持自定义的删除功 能。这可以防止 “ 跨 DLL 问题 ” ,可以应用在自动解开互斥锁等情况下
第4条: 要像设计类型一样设计 class
l 新类型的对象的成员变量的访问属性,一般是private,极少protected,一般不public。另外,它们的文件访问属性,static or not
l 新类型的对象应如何创建和删除? 类中与之相关的函数包括:构造函数和析构函数,以及类中其它的内存分配和释放函数( operator new 、 operator new[] 、 operator delete 、 operator delete[])。如果你自己手动编写它们,这个问题的解决方式将会影响到这些函数。
l 如何检验初始化的数据的合法性?如果不合法,如何处理,传统防错式编程还是抛出异常?如果抛出异常,又会影响哪些函数?
l 对象的拷贝与赋值
l 应明确拒绝哪些标准函数? 通过将它们声明为 private 的可达到这一目的
l 新类型是否适用于继承? 如果新类是由现成的类继承而来的,那么就必须让新类符合继承的特征,尤其是要确定父类的成员函数是否应为虚函数。
l 新类型允许进行哪些类型转换?单参数构造函数 explicit or not
l 运算符的重载,包括 可以重载[1]哪些运算符,成员形式,友元形式,非成员非友元形式, 另外,还有输入形参,返回参数的形式
l 新类型中有哪些“尚未声明的接口”? 新类型中提供了哪些性能、异常安全(参见第 29 条)、资源使用的保证(比如互斥锁、动态内存)?这些保证将会为类的实现提供更严格的约束。
l 这个新类型是否满足了需求? 如果你创建新的派生类仅仅为了为现有的类添加新的功能,那么通过简单地定义一个或多个非成员函数或者模板可能会更好的达到目标。
第5条: 尽量使用“引用常量”传参,而不是传值
l 尽量使用引用常量传参,而不是传值方式。因为传引用更高效,而且可以避免“截断问题”[2]。
第6条: 在必须返回一个对象时,不要去尝试返回一个引用,对于局部的 / 分配于栈上 / 分配于堆上的对象,如果你需要将其中的任意一种作为函数的返回值,请确保做到以下几点:不要返回一个指向局部的、分配于栈上的对象;不要返回一个引用去指向分配于堆上的对象;不要返回一个指向局部静态对象的指针或引用。
第7条: 尽量将数据成员声明为私有的。要将数据成员声明为私有的。这样可以让客户端访问数据时拥有一致的语义,提供有条不紊的访问控制,强制类符合一致性,为类作者提供更高的灵活性。[3]
第8条: 尽量使用非成员非友元函数,而不是成员函数[4]。实质是一个类接口完整且最小的问题。
第15+9条: 当函数所有的参数需要进行类型转换时,要将其声明为非成员函数
[1] “可以重载”,想强调的就是运算符重载一定要谨慎,很多错误都是跟运算符重载有关的。如果想重载运算符,那么它的意义一定要直观,而且第一感觉下不会产生任何误解。
[2] 除开效率和头疼的截断问题外,传值没有什么不好,特别在多线程情况下,可以避免引用一般要考虑的同步问题。但重要的一点还是,这里是在C++,编程也要讲适应环境,大部分代码都是用传引用,如果你传值,在涉及截断问题的代码上是让人很困惑的:这里是会截断呢还是不会截断呢?
[3] 关键一句话:可以虽然更改内部实现,但不改动外部接口和代码。
[4] 这不是鼓励你使用POD+C函数。首先,应该保证接口完整。其次,因为C++有名字空间,你可以将这些函数放置在同名空间或者关联的名字空间,并在单独的头文件中定义,这样可以保证不会出现标准string的尴尬。