bug源于:
http://hi.baidu.com/luosiyong/item/1c1f63c35414e027e90f2ee0
还能找到这句代码:
m_pGameWnd = FindWindow(m_classname.GetLength() > 0 ? m_classname : NULL, m_windowname);
本意是如果m_classname是空字符串,则传NULL为FindWindow的第一个参数,否则传m_classname。
如果m_classname是非空字符串的时候,上面代码正常,如果是空字符串的时候,我们把问题简化如下:
CString str = "";
const char *p = false ? str : NULL;
分析下上面一行代码的结果p是什么?从表面来看,简单的三元运算符,并且条件还是false,那一定该是NULL了?
如果str是一个const char *或者char *,那么这样的结论是正确的。
但是str是一个CString,这样的结论就错了……
运行环境在Visual Studio 2010,偶然发现了这个bug,经查,结果是这样的:
三元运算符冒号前面是CString,因此编译器将后面的NULL也拿去构造了一个CString,然后再赋值给p。因此p非空,而是指向了由NULL构造出来的CString里面数据的地址!
Visual Studio 2010跟踪发现会调用如下两段关键代码:
cstringt.h: //用NULL构造CString对象
CStringT(_In_opt_z_ const XCHAR* pszSrc) :
CThisSimpleString( StringTraits::GetDefaultManager() )
{
if( !CheckImplicitLoad( pszSrc ) )
{
*this = pszSrc;
}
}
atlsimpstr.h: // 将CString转成const char *以便赋值给p
operator PCXSTR() const throw()
{
return( m_pszData );
}
同样的代码,在VC6.0中则会报告如下的编译错误:
error C2446: ':' : no conversion from 'const int' to 'class CString' No constructor could take the source type, or constructor overload resolution was ambiguous
总结:
不要对不同类型使用三元运算符,因为上面所述的隐式类型转换可能会带来非预期的效果!