MC++ FAQ
Tuesday 07 | 16 | 2002
String Comparisions
Here's how String Interning for System::String instances and literal strings in your code relates to string comparisions on MC++.

If you've been trying to use the == operator to compare managed string instances and have been getting inconsisten results, then string literals are probably involved. This is not really tricky, but the fact that the problem is that you're seeing how string Interning works is not obvious.

Consider this simple code:

String* s1 = S"This is a String";
String* s2 = S"This is a String";

// s1==s2 && s1.Equals(s2)==true
Console::WriteLine(S"s1==s2 - {0}", __box(s1==s2)); 
Console::WriteLine(S"s1.Equals(s2) - {0}",  __box(s1->Equals(s2)));

The code above should print true for both cases. However, now add this:

String* s3 = "This is a String";
	
// s1!=s3 && s1.Equals(s3)==true
Console::WriteLine(S"s1==s3 - {0}", __box(s1==s3)); 
Console::WriteLine(S"s1.Equals(s3) - {0}",  __box(s1->Equals(s3)));

Now it prints false and true. So what's going on?

The problem is you're expecting your use of == to imply the use of the managed equality operator (also known as op_Equality()), just as similar-looking C# code would do. However, that's not the case. Since String is a reference type you're accessing through pointers, standard C++ syntax demands that a pointer comparision is done, so what you're really doing is comparing the two pointer values for equality.

So why does it work in the first case? The reason is that you're using the S prefix on your string literals. That tells the compiler you want this as a managed string, so the compiler will use the String Interning and String Pooling features of the .NET runtime (see Jeffrey Richter's "Progamming the .NET Framework" for more details on this), and that means that you're not actually creating two String instances with the same value, but rather retrieving pointers to the same String instance. That's why the pointer value comparision returns true!. BTW, this is all possible in great part thanks to the immutability of the String objects.

The second case does not do this, however, as you're not using the S prefix on the string literal. In that case, the compiler will generate code that will call one of String's constructors taking an unmanaged array of single-byte characters, which doesn't use interning, nor pooling, so the string is rather treated as a dynamically created string whose value is not known until runtime, if you see what I mean.

The lesson? Don't relly on the use of operator==; instead, use the Equals() method of the String class explicitly. That's the correct choice in this case, and in all cases where managed reference types are involved, since MC++ doesn't support overloaded managed operators on them.

Posted by tomasr at July 16, 2002 04:04 AM
Comments

Hi Tomas

Another technique that can be used is to cast both the unmanaged string literal and the String* to CString.

For example :-
String* s1 = S"Hello World";
String* s2 = "Hello World";

Now ((CString)s1==(CString)s2) is true

Regards,
Nish

Posted by: Nish on July 22, 2002 04:49 AM

Nish,

Thanks for the comment. I just want to add that while this can be a viable alternative, it doesn't make much sense unless your application already depends heavily on MFC and/or ATL.

Posted by: Tomas Restrepo on July 23, 2002 12:14 AM

Nish,

The problem with "casting to CString" is that it is not a cast, but a conversion - the string(s) will be copied into new instances of CString, which will be compared and then destroyed. If the strings in question are long, this could be a huge waste of CPU cycles.

Posted by: Carl Daniel on August 16, 2002 01:17 PM

You'd like to be able to do this...
*s1 == *s3
and have it call the Op_Equality for you. Unfortuantely System::String doesn't define the operator on references, only pointers (even though it's only a syntactic/metadata difference).
You can certainly do it in your own classes that are written in MC++. Here's an example with a String wrapper.

#using "mscorlib.dll"

using namespace System;

__gc class MyString{
String* str;
public:
MyString(String* s) : str(s) {}
static String* op_Implicit(MyString& ms){
return ms.str;
}
static bool op_Equality(MyString& a, MyString& b){
return String::op_Equality(a.str, b.str);
}
};

int _tmain()
{
String* s1 = S"Hello World.";
String* s3 = "Hello World.";
Console::WriteLine((String::op_Equality(s1, s3)).ToString());

MyString* ms1 = new MyString(s1);
MyString* ms3 = new MyString(s3);
Console::WriteLine((*ms1 == *ms3).ToString());

return 0;
}

Posted by: Adam on July 11, 2003 10:42 PM

Can any one help in comparing 2 string using wild card characters.
Eg Lets say I use std wildcard characters : '*' for 0 or more characters and '?' for exactly 1 character. I shud be able to compare two strings which may have these wild card characters. i.e. "SAMUEL" = "SA*L"

Thanks,
Mamta

Posted by: M on August 18, 2003 11:38 AM
Post a comment
Name:


Email Address:


URL:


Comments:


Remember info?

Copyright(C) 2002, Tomas Restrepo, All rights reserved. Powered by Movable Type 2.63