After programming in MFC for a few decades, many new projects that I started used MFC merely because I was so accustomed to the CString class. Even to the point that I integrated MFC in those projects just to use the
CString class. A few attempts to do away with MFC altogether failed. Not because std::string is not a good
string class, but because of the familiarity with all the methods of the former
string class. Besides,
CString knows of a few good tricks that you occasionally just need, like getting BSTR-ings, getting an environment variable, or all sorts of tricks like ‘
FormatV’ where you would otherwise need an extra function. So I would half-way through some algorithm be stuck trying to remember ‘how-to-do-this-in-this-string-class’ anyway. That would then interrupt my train of thoughts. This roundtrip through some
string operation would often cause a distraction of the work at hand.
One Solution: Study Harder
A solution would of course be to study harder on
std::string. But knowledge is not just the one solution. Literally, million of lines of code are hanging around. Not only in my private projects, but also at the office. At work, we need to support millions of lines of code with MFC’s
CString in them. So I would always be betting on two horses and trying not to mix them both up.
Another Solution: Elimination
Another possibility would obviously be to eliminate one of those classes. Preferably, the older one (MFC
CString) would have to go. There is no reason why you cannot add
std::string to a mixed source base with other classes in it. And I was already using the STL containers like ‘
map’ and ‘
multimap’ everywhere in favor of the old MFC containers. But still: this would be a lot of work with no extras like extra functionality attached to it.
My Solution: Integration
The road chosen here was to integrate the two of them. Derive a new class from
std::string, so the new class has all the standard functionality of the STL standard
string class. And then, add all the MFC
CString methods to that class. So we would have both of them at the same time.
Now I hear you thinking: “YUK!” What a horrible thing to do!
Yeah. I know! The end result is NOT a nice and comprehensive class. But wait…. The winning part is not in this end result. The winning part is when you are programming and do not want to stop doing what you are doing. All the things you would be required to remember are now wrapped inside the new
Another winning property is that you can use it as a drop-in replacement.
The new class is called “
SMX_String” which stands for “Standard MFC eXtended String”. The interface definition in the “SMX_String.h” file is ended with a choice of name overrides. Here, we choose a more handsome name to program in. The first case being just “
String”, as defined by a
Just in case we have a project at hand with only a
CString in it, we can rename the
CString with a
typedef to our new class. We could even rename a “
std::string” with a macro (but that is not a nice solution).
typedef SMX_String String;
The End Result: Both Sets of Methods Are Accessible
And there you have it. You can now have a project without MFC and a
string class that can do both the tricks of
MFC::CString in one package.
We can now do everything with a “
String” that we want. In the example above, you can see that you can do both “
c_str()” and “
GetString()” and that a “
Left(n)” is also working. No need to go over millions of lines of code to eliminate all those “
What’s Not Working
And of course, there are a few things that are definitely not working. That would need a lot of reworking on a
std::string to get working at all. Here are those few things:
- The default (LPCTSTR) casts will never work.
CString is using an elaborate scheme with a
StringData object, so that a pointer to a class object coincides with the storage of the
string data. Which in its turn makes it possible to dereference a memory pointer directly as in the fourth ‘
printf’ example here above;
std::string class does not have a locking scheme. You will need to do your locking outside of the
- Refcounting. But we have autopointers in the standard library!
- Copy on write (COW). Clearly for single-threaded programs with small
strings, a fine thing to have. But COW has been banned from the standard library. See some of the arguments by Herb Sutter here and by Giovanni Dicanio here.
Some Details That (might) Bite You
There are a few details that you should be aware of, or otherwise they **will** bite you!
- Take good care of the “Advanced project settings” in Visual Studio. Especially, the “Use MFC” setting;
- Take good care of the standard precompiled header settings and any ‘stdafx.h’ that is still in use in your projects. I forgot about them in a good number of projects. Remove the “
#include <afx.h>” and other settings or convert to the newer convention of using a “pch.h” file.
Well that’s about all. Have fun with the “
- 29th September, 2019: Initial version