1. 防止类型收窄
(1)类型收窄:指的是导致数据内容发生变化或者精度丢失的隐式类型转换。
(2)类型收窄的几种情况:
①从浮点数隐式转换为整型数,如 int i = 2.2;
②从高精度浮点数隐式转换为低精度浮点数。如从 long double 转 double 或 float。
③从整型数隐式转换为浮点数,并且超出浮点数的表示范围,如 floa t= (unsigned long long) - 1,注意这表示将 -1先强制转换为unsigned long long,再隐式转换为 float。
④从整型数隐式转换为长度较短的整型数,并且超出其表示范围。如 char x = 65536。
(3)在C++98/03中,类型收窄编译器不会报错,而C++11中可以通过列表初始化来检查及防止类型收窄。
2. explicit关键字
(1)explicit用于阻止编译器的隐式转换,一般用于修饰构造函数。
(2)C++98/03由于不能使用{}列表初始化,即隐式转换只发生在调用带一个参数的构造函数中。但C++11允许用{}列表初始化对象,这可能会隐式调用带多个参数的构造函数。
(3)C++11中,explicit可用于修饰带多个参数的构造函数以防止隐式转换。(注意C++98/03中explicit被用于修饰只带一个参数的构造函数,如果修饰带多个参数的构造函数则无效)
使用取值范围较大的变量来初始化取值范围较小的变量时,将面临出现缩窄转换错误的风险,因为编译器必须将大得多的值存储到容量没那么大的变量中,下面是一个这样的示例:
int largeNum = 5000000;
short smallNum = largeNum; // compiles OK, yet narrowing error
缩窄转换并非只能在整型之间进行,但如果使用 double 值来初始化 float 变量、使用 int 值来初始化 float 或 double 变量,或者使用 float 值来初始化 int 变量,可能导致缩窄转换错误。有些编译器可能发出警告,但这种警告并不会导致程序无法通过编译。在这种情况下,程序可能在运行阶段出现 bug,但这种 bug 并非每次运行时都会出现。
为避免这种问题, C++11 引入了列表初始化来禁止缩窄。要使用这种功能,可将用于初始化的变量或值放在大括号( {})内。列表初始化的语法如下:
int largeNum = 5000000;
short anotherNum{ largeNum }; // error! Amend types
int anotherNum{ largeNum }; // OK!
float someFloat{ largeNum }; // error! An int may be narrowed
float someFloat{ 5000000 }; // OK! 5000000 can be accomodated
这种功能的作用虽然不明显,但可避免在执行阶段对数据进行缩窄转换导致的 bug:这种 bug 是不合理的初始化导致的,难以发现。
该文章会更新,欢迎大家批评指正。
推荐一个零声学院免费公开课程,个人觉得老师讲得不错,
分享给大家:Linux,Nginx,ZeroMQ,MySQL,Redis,
fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,
TCP/IP,协程,DPDK等技术内容,点击立即学习:
服务器课程:C++服务器