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.
The console application (using MFC as shared dll and Unicode charachter set) executes this simple function:
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!
The documentation for the CStringT Class contains the following cryptic statement:
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.
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 )
which in turn calls
void Append( PCXSTR pszSrc, int nLength )
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.
To me, this appears to be a bug in the implementation. Incidentally, if you reverse the arguments to
x += r; vs.
r += x;), the result is a string with length 2, as expected.
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.
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());).
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)".