欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

C++隐式转换的那些事

程序员文章站 2022-03-02 21:09:19
...

昨天在公司干活的时候遇到一个C++隐式转换的问题, 折腾了很久, 后来碰巧发现了一丝线索, 才得以解决. 废话不多说了, 先上代码:

 

// 此数组模板类声明
template
class SomeArray {

SomeArray(int physicalLength = 32, int growLength = 32);
...

int append(const T& value);
AcArray& append(const AcArray& otherArray);

...
};

// 枚举类型
enum Format { kFirst, ..., kLast };

// 问题代码
SOME_FUNC(...) {
    ...
    SomeArray<Format> fmtArray;
    ...
    for (int fmt = kFirst; fmt <= kLast; ++fmt) {
        if (fmt satisfy some condition) fmtArray.append(fmt);
    }
}

 

   上述问题代码在执行循环的时候, 明明append元素这条语句执行了, 但是fmtArray仍然为空. 于是我就在这条语句处设置 了断点, 然后F11进去看. 结果发现跳转到了SomeArray的构造函数里. 然后我又尝试了几次, 发现还是如此. 我就纳闷, 难道我构建出来的二进制出错导致link不对? 不可能啊, 这是一个模板类, 不需要link啊. 又或者是因为这个模板类是编译在一个pch文件里, 那个文件被弄dirty了? 尝试了一下, 发现不是由于link或者pch导致的. 没办法了, 下班前, 开始做了一个fully clean build(2 ~ 3小时), 希望排除某些模块的dirty所导致的问题.

 

    今天上班后, 和同事J继续调试, 发现, 居然还是继续跳入构造函数. 构造函数调用完毕后, 退回到append元素语句处. 这时候奇迹发生了: 同事J手一不小心, 又按了一下F11, 结果, 居然跳入了append函数内部. 这个append函数并不是append一个元素, 而是一个SomeArray<Format> 对象, 但是这个对象是空的. 执行完毕这个函数后,  继续按F11, 结果跳到了SomeArray的析构函数. 到这里, 问题基本上已经很清楚了:

 

    由于fmt是一个整形值, 那么C++在解析重载append函数时, 由于Integer->Enumeration的转换不能自动进行, 所以编译器倾向于寻找一条更可行的转换链: int -> SomeArray<Format>, 因为默认构造函数支持这种转换. 于是, 你所append的每个元素, 都用来作为构建临时数组对象时所使用的physicalLength 参数值. 最终得到的fmtArray也因为append了一堆空数组而始终为空.

 

    从这个问题, 我得到两个结论:

       

         1. C++的类型转换的确诡异, 自己平时编写的时候, 一定要注意适当地使用explicit关键字,避免不必要的隐式转换.

 

         2. 遇到诡异的事情, 还是要沉着冷静, 利用已有的信息去进行深入的分析, 不放过每个可疑的线索.

相关标签: C C++ C# J#