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

Nic*_*igh 6 c++ mfc visual-studio visual-c++ 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!
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

几个星期前我微软提交了一个错误,但到目前为止我还没有得到这些人的回答.

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

IIn*_*ble 6

CStringT类的文档包含以下隐含声明:

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

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

分析:

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

CSimpleStringT& operator+=( const CSimpleStringT& strSrc )
Run Code Online (Sandbox Code Playgroud)

overload,通过调用修改当前实例

void Append( const CSimpleStringT& strSrc )
Run Code Online (Sandbox Code Playgroud)

反过来打电话

void Append( PCXSTR pszSrc, int nLength )
Run Code Online (Sandbox Code Playgroud)

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

结果:

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

解析度:

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

如果您无法说服Microsoft修复该错误,那么您唯一的另一个选择是不要使用具有不良行为的运算符.一种方法是使用另一个字符串类.一个成熟的替代品是std :: wstring,你可以将其转换为CStringW必要的地方(CStringW cstr(s.c_str(), s.length());).


更新(2016-09-13):

OP向微软提交了一份缺陷报告,他们承认了这个漏洞.实现了一个错误修复,但"它将在下一个主要版本的库(它们可能不一定在当前[2016-03-31] Visual Studio vNext中发布)中出现".