|
Broken links? Email us! |
|
As much as I use and appreciate the Standard C++
Library, I've never liked its string template - basic_string<>
. At times it seems the designers went
out of their way to make it difficult to
use.
On the other hand, I've always loved the ease of use of MFC's CString
class. It checks for NULL pointers, implicitly converts to const
TCHAR*, and has some very handy member functions (Format, Load, etc) that make
string programming a breeze. But of course, I don't want to use MFC
anymore. In fact, I don't want to rely on any proprietary library because
I want portability.
Therefore I decided to combine the best of both worlds and create:
CStdString
This is a class (a template instantiation actually) that derives from from
basic_string<TCHAR>
. To the basic_string
it adds
the entire CString
API. You get CString
ease of use with 100%
basic_string
compatiblity. In short, a
CStdString object is a basic_string that
(with very few exceptions (noted below) it is also a drop-in
replacement for CString
. The best part of this is that both
APIs (basic_string and CString) are well known and well documented.
I originally submitted this article to another code site (which shall remain nameless :)) a few years ago. I like CodeProject so much I thought I'd submit it here too. I have used this class in almost every professional project I've done over the past 4 years. It has proven to be the single most useful piece of code I've ever written. It is also extensively debugged. I hope you like it. If you ever have any problems with it, please e-mail me. I'm happy to help.
I provided a simple source application here to prove some of the CString
functions work but it's really
just a token. The list of sample projects out there that use
CString and/or basic_string is massive.
CString
(see below for exceptions)
CStdStringW
and char-based version CStdStringA
.
The name CStdString
is just a typedef
of one of these two.
CString
) in all functions
CStdString
objects to and from DCOM IStreams.
basic_string
)
basic_string
and adds no
virtual functionsThere are a couple of issues about this code of that I should point out.
I was unable to exactly reproduce the CString
API. There
are a two functions that both CString
and basic_string
; share, but
implement differently. In these cases, I felt it best to make CStdString
behave like
basic_string
(the base class) rather than CString
. To be specific.
CStdString::operator[]
returns characters by
value (unlike CString
which returns them byreference<)
CString
declares them. That's the order that basic_string<>
;
needs and it was impossible to implement both versions.There were also two CString
functions I could not
implement at all -- LockBuffer
and UnlockBuffer
.
The template I wrote derives from basic_string
, a class template without a
virtual destructor. Any introductory text to C++ will tell you that it is
dangerous to derive from a class without virtual a destructor. It can lead
to behavior that is undefined. So if you were to code the following
(deleting a CStdStringA
through a pointer to the base class) you would
technically get undefined behavior
std::string* pstr = new CStdStringA("Hi"); // assign DERIVED object to BASE pointer delete pstr; // delete DERIVED through BASE class pointer -- UNDEFINED
Personally, I don't think this is much of an
issue. I mean really how often do you actually do this with string
objects? I have rarely (if ever) needed to dynamically allocate a string
object on the heap. And if I ever do, I won't using a base-class
pointer. So if you don't do this, you'll never have to worry. In
fact, even if you do code this way, I doubt you'll have any problems with CStdString
. I
can tell you that at least with Microsoft Visual C++, even the above
code runs just fine with no errors or memory leaks. I doubt many other compilers would give you
problems either. However my doubt does not impose reality on the C++ world. Caveat
Emptor.
|
|