您的位置:首页 > 编程语言 > C语言/C++

C++坑点集合 - 1 隐式调用和默认实现的构造函数的坑

2016-03-20 14:13 387 查看
C++是一个编译器会替你在背后做很多事情的语言,包括模板实例化,按需要创造隐式的构造函数,默认构造你没有显式构造的成员,按需进行隐式转换和饮食构造等等,如果没有彻底了解清楚,就容易被这些编译器背后做好的事情坑到,这个系列文章就来总结我在写C++时遇到的各种坑。

 

所谓隐式调用和默认实现的构造函数,当你写一个赋值语句的时候,编译器会首先检查两个类型又没有直接实现的赋值函数,然后检查赋值左右的类型是否能做隐式转换和构造,转换或者构造好之后,再尝试进行拷贝或移动赋值。这时候,坑点来了,如果你有这么样的一个类:

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的,忘了
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: