条款53:不要轻忽编译器警告
Pay attention to compiler warnings.
在C++,编译器作者通常对于将会发生的事情比程序员有更好的领悟。例如,下面的例子很常见:
程序员希望以D::f重新定义virtual B::f,但其中有个错误:B::f是const成员函数,而在D中没声明。
class B {
public:
virtual void f() const;
};
class D : public B {
public:
virtual void f();
};
编译器可能会警告:
warning: D::f() hides virtual B::f()
// MSVC 2017警告 /Wall
“void D::f(void)”: 成员函数不重写任何基类虚拟成员函数
“void B::f(void) const”: 不重写基“B”中的虚拟成员函数;函数被隐藏
如果忽略了这个警告,可能会在f中修改数据成员,从而导致非预期行为,从而产生错误。
另外,不同的编译器有不同的警告标准。不可依赖编译器指出所有的错误。
小结
1)严肃对待编译器发出的警告信息。努力中编译器的最高警告等级下争取“无任何警告”的荣誉;
2)不要过度依赖编译器的警告能力,因为不同编译器对待事情多态度并不相同。一旦移植到另一个编译器上,原本依赖的警告信息有可能消失。
[======]
条款54:让自己熟悉包括TR1在内的标准程序库
Familiarize yourself with the standard library, including TR1.
加入TR1之前,C++98的C++标准程序库主要成分:
- STL(Standard Template Library,标准模板库),覆盖容器(containers如vector,string,map)、迭代器(iterators)、算法(algorithm如find,sort,transform)、函数对象(function objects如less,greator)、各种容器适配器(container adapter如stack、priority_queue)和函数对象适配器(function object adapters如mem_fun,not1)。
- iostream,覆盖用户自定义缓冲功能、国际化I/O,以及预先定义好的对象cin,cout,cerr,clog。
- 国际化支持,包括多区域(multiple activate locales)能力。像wchar_t(通常是16bits/char)和wstring(由wchar_ts组成的strings)等类型都对促进Unicode有所帮助。
- 数值处理,包括复数模板(complex)和纯数值数组(valarray)。
- 异常阶层体系(exception hierachy),包括base class exception及其derived class logic_error和runtime_error,以及更深继承的各个classes。
- C89标准库程序。
TR1详细叙述了14个新组件(components,即程序库技能单位),都放在std::tr1命名空间内。如shared_ptr全名是std::tr1::shared_ptr。主要的TR1组件包括:
- 智能指针(smart pointers)tr1::shared_ptr和tr1::weak_ptr。前者类似于内置指针,但会记录有多少个tr1::shared_ptrs共同指向同一个对象,即所谓reference counting(引用计数)。一旦对象的引用计数为0,即这样的指针被销毁,该对象就会被自动删除。在这非环形(acyclic)数据结构中防止资源泄漏很有帮助。 tr1::weak_ptr 能有效避免环形数据结构导致的资源泄漏问题。
- tr1::function,表示任何callable entity(可调用物,即函数或函数对象),只要签名符合目标。
以前,当我们想注册一个callback函数,接受一个int并返回一个string的函数作为参数,可以这样写:
void registerCallback(std::string func(int));
// 省略参数名称
void registerCallback(std::string (int));
这里“std::string (int)”是个函数签名。
而当我们有了tr1::function后,可以接受任何可调用物,只有它可以接受一个int或任何可以被转换为int的东西,并返回一个string或任何可以被转换为string的东西。
void registerCallback(std::tr1::function<std::string (int)> func);
// 参数func可以接受任何可调用物,只有其签名与“std::string (int)”一致即可
- tr1::bind,参数绑定,能做STL绑定器(binders)bind1st和bind2nd所做的每件事,而且更多。
其他TR1组件划分为2组。第1组提供彼此互不相干的独立机能:
- Hash tables,用来实现sets,multisets,maps和multi-maps。每个新容器的接口都以其前任(TR1之前的)对应容器塑模而成。这些名称:tr1::unordered_set, tr::unordered_multiset, tr1::unordered_map以及tr1::unordered_multimap。强调它们和set,multiset,map或multimap的不同:以hash为基础的这些TR1容器内的元素并无任何可预期的次序。
- 正则表达式(Regular expressions),包括以正则表达式为基础的字符串查找和替换,或是从某个匹配字符串得到另一个匹配字符串的逐一迭代(iteration)等。
- Tuples(变量组),标准程序库中pair template的新一代制品。pair只能持有2个对象,tr1::tuple可持有任意个数的对象。
- tr1::array,本质上是个“STL化”数组,即一个支持成员函数如begin和end的数组。不过,tr1::array大小固定,不使用动态内存。
- tr1::mem_fn,语句构造上与成员函数指针(member function pointers)一致。就像bind扩充C++98的bind1st和bind2nd的能力一样,mem_fn扩充了C++98的mem_fun和mem_fun_ref的能力。
- tr1::reference_wrapper,一个让reference的行为更像对象的设施,可以造成容器持有如reference。而容器实际上只能持有对象或指针。
- 随机数(random number)生成工具,超越了继承自C标准库程序的函数rand。
- 数学特殊函数,包括Laguerre(拉盖尔)多项式,Bessel( 贝塞尔)函数,完全椭圆积分(complete elliptic integrals),以及更多数学函数。
- C99兼容扩充。这是一大堆函数和模板(template),用来将许多新C99程序库特性带进C++。
第2组TR1组件由更精巧的template编程技术(template metapromming,模板元编程)构成:
- Type traits,一组traits class,用于编译器萃取出类型。
- tr1::result_of,该模板用来推导函数调用的返回类型。
注意:TR1并未对原有组件进行修改,而是对标准库程序的纯粹添加。
TR1本身只是一份文档,为了取得其所规范的机能,还需要取得实效代码,如使用Boost程序库,或C++11以上版本提供的标准程序库。
小结
1)C++标准程序库的主要机能由STL、iostream、locale(系统区域设置,即国家或地区设置)组成,并包含C99标准程序库。
2)TR1添加了智能指针(smart_ptr,如tr1::shared_ptr)、一般化函数指针(tr1::function)、hash-based容器、正则表达式(regular expression)以及另外10个组件的支持。
2)TR1自身只是一份规范,可以Boost程序库,或C++11标准程序库。
[======]
条款55:让自己熟悉Boost
Familiarize yourself with Boost.
Boost是一个C++开发者社群,可以自由下载其程序库,网址:https://www.boost.org/
Boost是C++标准程序库的beta版本(先行者),很多实验成熟的库函数,会慢慢转移到标准程序库中。
Boost程序库要对付的主题很多,主要包括:
- 字符串与文本处理,覆盖具备类型安全(type-safe)的printf-like格式化动作、正则表达式(TR1同类机能的基础),以及语汇单元切割(tokenizing)和解析(parsing)。
- 容器,覆盖“接口与STL相似且大小固定”的数组,大小可变的bitsets以及多维数组。
- 函数对象和高级编程,覆盖若干被用来作为TR1机能基础的程序库,如lambda。
- 泛型编程(Generic programming),覆盖一大组traits class(条款47)。
- 模板元编程(template metaprogramming,TMP,条款48),覆盖一个针对编译器assertions而写的程序库以及Boost MPL程序库。MPL支持编译器实物如type的STL-like数据结构。
- 数学和数值(Math and numberics),包括有理数、八元数和四元数、常见公约数(divisor)和少见的多重运算、随机数。
- 正确性与测试(Correctness and testing),覆盖用来将隐式模板接口(implicit template interface,条款41)形式化的程序,以及针对“测试优先”编程形态而设计的措施。
- 数据结构,覆盖类型安全(type-safe)的unions,以及tuple程序库。
- 语言间的支持(inter-language support),包括允许C++和Python之间的无缝互操作性(seamless interoperability)。
- 内存,覆盖Pool程序库,用来做出高效率而区块大小固定的分配器(条款50),以及多变化的智能指针(条款13),包括TR1智能指针。
- 杂项,包括CRC检验、日期和时间的处理,在文件系统上来回移动等。
注意:Boost没有提供整套编程方案,如没有针对GUI开发设计的程序库,也没有连通数据块的程序库。
小结
1)Boost是一个社群,也是一个网站,提供免费、源码开放、同僚复审的C++程序库开发。
2)Boost提供许多TR1组件实现品,以及其他许多程序库。
[======]