现在的位置: 首页 > 综合 > 正文

不要对不同类型使用三元运算符[C++]

2018年04月30日 ⁄ 综合 ⁄ 共 1057字 ⁄ 字号 评论关闭

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

总结:

不要对不同类型使用三元运算符,因为上面所述的隐式类型转换可能会带来非预期的效果!

抱歉!评论已关闭.