CString运算符之间的不同行为" + ="和" +"

时间:2016-01-27 17:34:47

标签: c++ visual-studio visual-c++ mfc visual-studio-2015

在将应用程序从VisualStudio 2005迁移到VisualStudio 2015时,我们在某些代码中发现了一种不同的行为,当使用VS2015构建该代码时,它会连接CString实例。 所以,我已经创建了一个简单的Win32控制台应用程序来演示这个问题。

控制台应用程序(使用MFC作为共享dll和Unicode charachter集)执行这个简单的功能:

void f()
{
   CString x( '\0' );

   CString r( 'a' );
   r += x;
   CString rr( 'a' );
   rr = rr + x;

   int rSize = r.GetLength();
   int rrSize = rr.GetLength();

   assert( rSize == rrSize ); // This assert fires when compiled and run 
                              // under Visual Studio 2015!
}

它表明,当一个CString包含' \ 0' char被连接到另一个CString实例,使用' + ='或使用' +'导致不同的结果!

当' + ='用于计算结果的大小计算所有字符直到第一个' \ 0' ...因此最终大小为1!
相反,当运营商' +'使用结果CString size为2,即连接实例的大小总和!

在VisualStudio 2005中,结果大小始终是连接实例大小的总和!

几周前,我filed a bug给了微软,但直到现在我还没有回复这些家伙。

我的问题:
 1.有人偶然发现了MCF库中的这个错误吗?  你是如何解决这个错误的?我们正在考虑禁止使用+ =运算符或者用自定义类替换CString类,但所有这些对我而言似乎都是一个"侵入性的。

1 个答案:

答案 0 :(得分:6)

CStringT Class的文档包含以下神秘声明:

  

虽然可以创建包含嵌入空字符的CStringT实例,但我们建议不要使用它。 在包含嵌入空字符的CStringT对象上调用方法和运算符会产生意外结果。

坦率地说,我真的不知道该怎么做最后一句话。我把它作为一个警告,在嵌入空字符时要小心。无论如何,合同保证在这样做时仍应保留。

<强>分析:

CStringT::operator+=显然不是这种情况。在问题的示例代码中,operator+=的实现调用

CSimpleStringT& operator+=( const CSimpleStringT& strSrc )

重载,通过调用

修改当前实例
void Append( const CSimpleStringT& strSrc )

反过来调用

void Append( PCXSTR pszSrc, int nLength )

传递显式长度参数。这应该足以处理带有嵌入空字符的C风格字符串。奇怪的是,然后实现开始通过调用StringLengthN(pszSrc, nLength)(实现为对wcsnlen的调用)来猜测输入,以重新计算 pszSrc 的长度。这将为示例代码中的CStringT实例 x 返回0。

<强>结果:

对我而言,这似乎是实施中的一个错误。顺便提一下,如果您将参数反转为operator+=(即x += r;r += x;),则结果是一个长度为2的字符串,如预期的那样。

解决:

唯一干净的解决方案是让微软承认错误,并提供修复程序。但是,我不会屏住呼吸,因为微软通常不会发布错误修复,如果它们改变了发货产品的行为。

如果您无法说服Microsoft修复该错误,那么您唯一的另一个选择就是不要将操作符用于不受欢迎的行为。一种方法是使用另一个字符串类。一个完善的替代品是std::wstring,您可以在必要时将其转换为CStringWCStringW cstr(s.c_str(), s.length());)。

<小时/> 更新(2016-09-13):

OP向微软提出defect report,他们承认了这个错误。实现了一个错误修复,但“它将不会出现在库的下一个主要版本(可能不一定在当前[2016-03-31] Visual Studio vNext中发布)”