C++坑点集合 - 1 隐式调用和默认实现的构造函数的坑
2016-03-20 14:13
387 查看
C++是一个编译器会替你在背后做很多事情的语言,包括模板实例化,按需要创造隐式的构造函数,默认构造你没有显式构造的成员,按需进行隐式转换和饮食构造等等,如果没有彻底了解清楚,就容易被这些编译器背后做好的事情坑到,这个系列文章就来总结我在写C++时遇到的各种坑。
所谓隐式调用和默认实现的构造函数,当你写一个赋值语句的时候,编译器会首先检查两个类型又没有直接实现的赋值函数,然后检查赋值左右的类型是否能做隐式转换和构造,转换或者构造好之后,再尝试进行拷贝或移动赋值。这时候,坑点来了,如果你有这么样的一个类:
看它的构造函数,每一个参数都有默认参数,这个东西是会被编译器当成默认构造函数的,并且这个构造函数不会被视为用户自己实现的构造函数,所以编译器依然会按需自动生成其他的[拷贝|移动][构造|赋值]函数,所以这时候坑点来了,以下的语句是合法的:
label = 2,这条语句会让编译器隐式调用Token的构造函数用2构造一个Token,参数的_content采用默认值“”,然后又调用隐式生成的移动赋值(move assignment)函数,进行赋值。而且毫无警告发生,这样写可能还比较明显,容易发现问题,如果代码复杂起来,被坑的可能性就大大提高了,我自己的tokenizer generator就是有一个bug坑在了这个地方,幸亏IDE能识别出运算符重载以及显示鼠标指向的变量的值,让我很快发现了这个bug,不然又不知道要debug到猴年马月去了。这个问题还说明了使用一个牛逼的IDE的重要性,倘若是用VC6……呵呵呵呵呵。
话说我该把这个构造函数声明为explicit的,忘了
所谓隐式调用和默认实现的构造函数,当你写一个赋值语句的时候,编译器会首先检查两个类型又没有直接实现的赋值函数,然后检查赋值左右的类型是否能做隐式转换和构造,转换或者构造好之后,再尝试进行拷贝或移动赋值。这时候,坑点来了,如果你有这么样的一个类:
struct Token { int label; string content; Token(int _label = -1, string _content = "") : label(_label) , content(_content) {} };
看它的构造函数,每一个参数都有默认参数,这个东西是会被编译器当成默认构造函数的,并且这个构造函数不会被视为用户自己实现的构造函数,所以编译器依然会按需自动生成其他的[拷贝|移动][构造|赋值]函数,所以这时候坑点来了,以下的语句是合法的:
Token label(1, "hello"); label = 2; //这tm是合法的!!!
label = 2,这条语句会让编译器隐式调用Token的构造函数用2构造一个Token,参数的_content采用默认值“”,然后又调用隐式生成的移动赋值(move assignment)函数,进行赋值。而且毫无警告发生,这样写可能还比较明显,容易发现问题,如果代码复杂起来,被坑的可能性就大大提高了,我自己的tokenizer generator就是有一个bug坑在了这个地方,幸亏IDE能识别出运算符重载以及显示鼠标指向的变量的值,让我很快发现了这个bug,不然又不知道要debug到猴年马月去了。这个问题还说明了使用一个牛逼的IDE的重要性,倘若是用VC6……呵呵呵呵呵。
话说我该把这个构造函数声明为explicit的,忘了
相关文章推荐
- 探索C++0x: 1. 静态断言(static_assert)
- 5-18 二分法求多项式单根 C语言版
- 5-20 打印九九口诀表 (15分)c语言
- 5-19 支票面额 (15分)C语言
- 贪心算法—移动办公室桌子,占用走廊问题(1000,problem A)
- 1057. Stack (30)
- C语言中内存分配问题
- 排序——冒泡排序(C++)
- C语言第三篇:C语言数据类型及各数据类型所占内存字节数
- c语言将数组全部赋0的方法
- C语言之辗转相除法
- C语言之冒泡排序算法
- 转载一篇对C语言中可变参数的文章
- C语言通过位运算筛选出字符串中的中文
- C++11尝鲜:std::move和std::forward源码分析
- usaco 2.3.1 prefix
- usaco 2.1.5 hamming
- 模糊数的C++实现
- C语言两种定义字符串的方式
- YMS Round #1 Div. 2 C Mowing the Field