CString 运算符“+="之间的不同行为和“+" [英] Different behaviour between CString operators "+=" and "+"

查看:96
本文介绍了CString 运算符“+="之间的不同行为和“+"的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

While migrating an application from VisualStudio 2005 to VisualStudio 2015 we found a different behaviour in some code that concatenates CString instances when that code is built with VS2015.
So, I've created a simple Win32 console application to demonstrate the problem.

控制台应用程序(使用 MFC 作为共享 dll 和 Unicode 字符集)执行这个简单的函数:

The console application (using MFC as shared dll and Unicode charachter set) executes this simple function:

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!
}

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

It shows that, when a CString containing a '\0' char is concatenated to another CString instance, using '+=' or using '+' leads to different results!

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

When '+=' is used the size of the result is calculated counting all chars till the first '\0'... hence the final size is 1!
Conversely, when the operator '+' is used the result CString size is 2, that is the sum of the sizes of the concatenated instances!

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

In VisualStudio 2005 the result size is always the sum of the sizes of the concatenated instances!

我在几周前向 Microsoft 提交了一个错误,但直到现在我没有得到那些家伙的答复.

I filed a bug to Microsoft a few weeks ago, but up until now I have no answer from those guys.

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

My questions:
1. Have somebody stumbled onto this bug in the MCF library??
2. How have you worked around this bug? We are thinking to ban the use of the += operator or else to replace the CString class with the a custom class, but all of this seems to me "a bit" invasive.

推荐答案

CStringT 类 包含以下神秘语句:

虽然可以创建包含嵌入空字符的 CStringT 实例,但我们建议不要这样做.对包含嵌入空字符的 CStringT 对象调用方法和运算符可能会产生意想不到的结果.

Although it is possible to create CStringT instances that contain embedded null characters, we recommend against it. Calling methods and operators on CStringT objects that contain embedded null characters can produce unintended results.

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

Frankly, I don't really know what to make of the final sentence. I take it as a warning to be careful when embedding null characters. Regardless, contractual guarantees should still hold when doing so.

分析:

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

This apparently is not the case with CStringT::operator+=, though. In the sample code of the question the implementation of operator+= invokes the

CSimpleStringT& operator+=( const CSimpleStringT& strSrc )

重载,通过调用修改当前实例

overload, which modifies the current instance by calling

void Append( const CSimpleStringT& strSrc )

反过来调用

void Append( PCXSTR pszSrc, int nLength )

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

passing an explicit length argument. This should suffice to deal with C-style strings with embedded null characters. Oddly enough, the implementation then starts to second-guess the input by calling StringLengthN(pszSrc, nLength) (implemented as a call to wcsnlen), to re-calculate the length of pszSrc. This returns 0 for the CStringT instance x in the sample code.

结果:

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

To me, this appears to be a bug in the implementation. Incidentally, if you reverse the arguments to operator+= (i.e. x += r; vs. r += x;), the result is a string with length 2, as expected.

分辨率:

唯一干净的解决方案是让 Microsoft 承认该错误,并为其提供修复.不过,我不会屏住呼吸,因为 Microsoft 通常不会发布错误修复程序,如果他们更改已发布产品的行为.

The only clean solution would be to have Microsoft acknowledge the bug, and provide a fix for it. I wouldn't hold my breath, though, as Microsoft usually doesn't ship bug fixes, if they change behavior of a shipped product.

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

If you cannot convince Microsoft to fix that bug, your only other option is to not use the operator with undesired behavior. One way would be to use another string class. A well established replacement is std::wstring, which you can convert to a CStringW where necessary (CStringW cstr(s.c_str(), s.length());).


更新 (2016-09-13):

OP 向 Microsoft 提交了缺陷报告,他们承认了该错误.已实施错误修复,但直到库的下一个主要版本(可能不一定在当前 [2016-03-31] Visual Studio vNext 中发布)才会出现".

The OP filed a defect report with Microsoft, and they acknowledged the bug. A bug fix was implemented, but "it won't appear until the next major version of the libraries (which may not necessarily ship in the current [2016-03-31] Visual Studio vNext)".

这篇关于CString 运算符“+="之间的不同行为和“+"的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆