读书笔记 Effective C++(4)

41、了解隐式接口和编译期多态

类和模板都支持接口和多态,对类而言,接口是显式的,以函数签名为中心,多态通过虚函数发生于运行期。

对模板参数而言,接口是隐式的,基于有效的表达式,多态通过模板具现化和函数重载解析发生于编译期。

42、了解typename的双重意义

作为模板参数,class和typename没有不同,可以互换。

当使用一个内嵌类型时,需要在前面加上typename,编译器才知道它是一个类型而不是成员或者函数。

1
2
3
4
5
template<typename T>
void Sample(T t){
typename std::iterator_traits<T>::value_type temp(T);
...
}

43、学习处理模板化基类内的名称

因为基类模板可能被特化不提供基类模板的某个函数,所以在派生类里面直接调用模板基类的函数无法通过编译,可以通过this指针和using声明或者基类作用域符号来告诉编译器假定该函数存在。

44、将与参数无关的代码抽离templates

模板生成多个类和函数,所以任何模板都不该与某个造成膨胀的模板参数产生相依关系。

用函数参数或者class成员变量代替模板参数可以消除这种膨胀。

还可以让具有完全相同的二进制表述的类型共享实现码,也可以减小膨胀,如int和long在一些机器上是一样的,所有指针类型都是一样的。

45、运用成员函数模板接受所有兼容类型

泛化构造函数可以使一个类型隐式转换成另一个类型:

1
2
3
4
5
6
7
8
9
10
template<class T>
class shared_ptr{
public:
...
template<class Y>
shared_ptr(shared_ptr<Y> const&); //泛化构造函数

templa<class Y>
shared_ptr& operator=(shared_ptr<Y> const&); //泛化赋值函数
}

声明了泛化构造函数还是需要声明正常的构造函数和赋值函数。

46、需要类型转换时请为模板定义非成员函数

当提供与模板相关的包含参数隐式转换的函数时,将函数定义为friend并在类内实现。

47、请使用traits classes表现类型信息

traits classes,特性萃取,使得类型相关信息在编译期可用,以template内嵌typedef和偏特化实现。

如何使用traits?

  • 建立一组重载函数,最后一个参数是traits的类型参数,对于不同的类型做实现。
  • 另外建立一个控制函数调用上述函数,传入traits的参数,此为双层结构,在STL中非常常见。

48、认识模板元编程(TMP)

TMP可以将工作从运行期搬到编译期,从而实现更早的错误侦测和更高的执行效率。还可以被用来生成“基于政策选择组合”的客户定制代码,也可以用来避免生成对某些特殊类型并不合适的代码。

1
2
3
4
5
6
7
8
9
template<unsigned n>
class Factorial{
enum{value = n * Factorial<n-1>::value};
}

template<>
class Factorial<0>{
enum{value = 1};
}

49、定制new和delete

set_new_handler允许客户制定一个函数,当内存分配失败时调用这个函数进行处理。

Nothrow new只适用于内存分配,如果构造函数出现问题还是可能抛出异常。

50、了解new和delete的合理替换时机

有许多理由需要写个自定义的new和delete,包括改善性能、对heap运用错误进行调试、收集heap调试信息等。

51、编写new和delete时需固守常规

operator new应该内含一个无穷循环,并在其中尝试分配内存,如果它无法满足内存要求,就该调用new_handler。它也应该有能力处理0bytes申请,class专属版本还应该处理“比正确大小更大的申请”。

operator delete应该在收到null指针时不做任何事情,class专属版本还应该处理“比正确大小更大的申请”。

52、写了placement new也要写placement delete

placement new只有placement delete能够delete,所以没有声明placement delete使用placement new的话会出现内存泄漏。

当在类内声明placement new和placement delete时会遮盖标准的new和delete,一种做法是将所有标准的new/delete放到一个基类里,然后要自定义new/delete的类继承这个基类,使用using声明获取标准形式。

53、不要轻忽编译器的警告

54、让自己熟悉包括TR1在内的标准程序库

C++标准库的主要机能由STL、iostream、locales组成,并包含C99标准程序库。

TR1添加了智能指针、一般化函数指针(function)、hash-based容器、正则表达式以及另外10个组件的支持。

TR1自身只是一个规范,为获得TR1提供的好处,需要一个实物,一个好的来源是Boost。

55、让自己熟悉Boost

Boost是一个社群,致力于免费、源码开放、同僚复审的C++程序库开发。Boost在C++标准化过程中扮演深具影响力的角色。
Boost提供了许多TR1组件实现品,以及其他许多程序库。

分享到