Click here to Skip to main content
15,886,026 members
Articles / Programming Languages / C++
Article

Yet another CString replacement (only much more practical)

Rate me:
Please Sign up or sign in to vote.
4.48/5 (25 votes)
1 Jul 20034 min read 166.6K   1.4K   28   60
MFC/non-MFC usage, UNICODE support, numerics operations support

Introduction

Its been almost 5 months since I'm involved in a very large Visual C++ project. The thing that I missed the most was a really practical string class.

<Getting political>

A good programmer is one that gets things done on time. Getting things done on time depends on the language you use and the available libraries. It's obvious that the language we use is C++, more exactly Visual C++. C++ is probably the most difficult language to master these days but we can't do anything about it, that's the standard and we have to live with it, and so we have a -(minus) on the "gets things done in time", which is almost always true from the point of view of management people. The only thing that can save us, besides years of experience, is good library support. The specific library support I will talk about in this article is, of course, string related and the keyword is practical.

On the MFC side I have CString, it's a decent string class implementation but I'm not very happy with it mainly for three reasons:

  1. I can use it only in MFC projects
  2. I cannot chain operations on a CString instance. Example:
    CString str( "  05 09 1990 ");    
    
    // I want to convert to "05/09/1990"
    str.TrimLeft();
    str.TrimRight();
    str.Replace( " ", "/" );

    By chaining operations I mean the following:

    str.TrimLeft().TrimRight().Replace( " ", "/" );

    See the difference? I don't know about you but I definitely do and I don't want to go back.

  3. Numeric operations support. This is something I used even in the smallest projects I've done. There's almost no way I can escape these conversion operations, and again CString doesn't do a good job to help me out. Of course CString provides Format and FormatV methods but they're not at all nice with me.
On the non-MFC side I have ( if you're a STL lover stop reading here ) well...almost nothing. Yes, I know there is std::string but I can't do much with it. It suffers the same drawbacks ( maybe more ) all STL does: too much academicism as oposed to practical, everything is so in place and standards aligned that I am nothing but delighted when I look at it. Unfortunately that's all about it.

</Getting political>

Using the code

The class name is CStr. I'll start directly with examples, I think the class interface is self-explanatory:

Chaining operations: The above CString example using the CStr class:

CStr str( "  05 09 1990 " );    
str.Trim().Replace( " ", "/" ); 

Numerical operations:

CStr str;
long lValue;
str = 123; 
lValue = str; // lValue -> 123;
        
// or if you don't like automatic conversion operators
double dValue;
str.SetDouble( 123.45 );
dValue = str.GetDouble(); // dValue -> 123.45;

Append operator ( denoted by << ) : Using this operator you can chain concatenation like this:

CStr str;
str << "Value=" << 12 << .5 << " seconds"; // str -> "Value=12.5 seconds";

Observations:

  • It is not the perfect string class but I like it, there will be bugs for sure in this implementation, so please let me know. If you think there are methods that must be added/changed also let me know, and if I like the proposals I'll change the interface.
  • In many cases are performed operations that modify the string length, and thus the size of the internal buffer, and to avoid some of memory reallocation cycles each new allocation adds an extra buffer size of
    CSTR_EXTRA_SIZE 
    (defined as static member). The default value is 16, if you don't want to use this feature and want to keep the buffer as small as possible set CSTR_EXTRA_SIZE value to 0.
  • Numerical conversion regarding double values is done using _vsntprintf and setting type field to "%g".
  • Though I wrote this class with full Unicode support I didn't have a chance to test it using Unicode, so it'll be great if someone can test it, before I'll use it in real projects ;).
  • The demo project is an empty MFC project that is full of ASSERTs that wrap CStr methods for testing, something like unit testing.

CStr public Interface

                static int CSTR_EXTRA_SIZE;

                CStr() throw();
                ~CStr();
                CStr( const CStr &str ) throw();
                CStr( LPCTSTR pszStr ) throw();
                CStr( int allocSize ) throw();

CStr&           operator = ( const CStr& str ) throw();
CStr&           operator = ( LPCTSTR pszStr ) throw();
CStr&           operator = ( int iValue ) throw();
CStr&           operator = ( long lValue ) throw();
CStr&           operator = ( unsigned long ulValue ) throw();
CStr&           operator = ( double dValue ) throw();
            
// internal buffer access
TCHAR*          Buffer() const;
TCHAR*          Buffer();
int             BufferSize() const;
BOOL            Realloc( int size ) throw();
void            Compact() throw();

// attributes
int             Length() const;
BOOL            IsEmpty() const;

// comparision
BOOL            operator == ( LPCTSTR pszStr ) const;
BOOL            operator != ( const LPCTSTR& str ) const;
int             Compare( LPCTSTR pszStr ) const;
int             CompareNoCase( LPCTSTR pszStr ) const;

// accessors
               operator LPCTSTR () const;
               operator int () const;
               operator long () const;
               operator unsigned long () const;
               operator double () const;

TCHAR&         operator [] ( int pos );
const TCHAR&   operator [] ( int pos ) const;
    
CStr           Left( int size ) const throw();
CStr           Right( int size ) const throw();
CStr           Mid( int start, int size ) const throw();
    
               // number of occurences
int            FindCount( LPCTSTR pszStr ) const; 
               // same as above only starting at startPos
int            FindCount( int startPos, LPCTSTR pszStr ) const; 
               // zero-based index of the 1st occurence
int            Find( LPCTSTR pszStr ) const;
               // zero-based index of the nth occurence
int            FindNth( int nth, LPCTSTR pszStr ) const;
               // zero-based index of the 1st occurence starting
               // from the end of the string
int            ReverseFind( LPCTSTR pszStr ) const;
               // zero-based index of the nth occurence starting
               // from the end of the string
int            ReverseFindNth( int nth, LPCTSTR pszStr ) const;

// operations
CStr&          Empty();
CStr&          Fill( const TCHAR chr );
CStr&          Trim();
CStr&          TrimLeft();
CStr&          TrimRight();
CStr&          Lower();
CStr&          Upper();
CStr&          Insert( int pos, LPCTSTR pszStr ) throw();
CStr&          Prepend( LPCTSTR pszStr ) throw();
CStr&          Append( LPCTSTR pszStr ) throw();
CStr&          Remove( int pos, int len ) throw();
CStr&          Trunc( int pos );
CStr&          Replace( LPCTSTR pszOld, LPCTSTR pszNew ) throw();
CStr&          Replace( int startPos, LPCTSTR pszOld, LPCTSTR pszNew ) throw();
CStr&          Format( LPCTSTR pszFormat, ... ) throw();
CStr&          FormatV( LPCTSTR pszFormat, va_list args ) throw();
    
// numerics ( get/set )
int            GetInt() const;
long           GetLong() const;
unsigned long  GetULong() const;
double         GetDouble() const;
CStr&          SetInt( const int iValue ) throw();
CStr&          SetLong( const long lValue ) throw();
CStr&          SetULong( const unsigned long ulValue ) throw();
CStr&          SetDouble( const double dValue ) throw();

// << concatenation operator
friend CStr&   operator << ( CStr &str, LPCTSTR pszStr ) throw();
friend CStr&   operator << ( CStr &str, int iValue ) throw();
friend CStr&   operator << ( CStr &str, long lValue ) throw();
friend CStr&   operator << ( CStr &str, unsigned long ulValue ) throw();
friend CStr&   operator << ( CStr &str, double dValue ) throw();

That's it. Have fun !

History

June 21, 2003

  • Replaced new/delete operators with malloc/free for internal buffer allocation/deallocation. It seems malloc is faster for large arrays.
  • If memory allocation fails the std::bad_alloc exception will be thrown. The methods that may throw this exception are marked with throw() in the class declaration.
  • As requested two new functions were adeded: FindNth( int nth, LPCTSTR pszStr ) const which returns the zero-based index of the nth occurence of pszStr. ReverseFindNth( int nth, LPCTSTR pszStr) const does the same thing only doing reverse search starting from the end of the string.
  • Contains method was renamed to the more suggestive FindCount.
  • All #defines replaced with static members, including CSTR_EXTRA_SIZE.
  • The CStr implementation was backed up by _ASSERTs.
  • Other small cleanups.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Romania Romania
Programmer

Comments and Discussions

 
Generali dun feel comfortable with "&lt;&lt;" Pin
f28-Jul-06 3:42
f28-Jul-06 3:42 
GeneralSome Useful CString extensions Pin
dgendreau14-Nov-05 17:13
dgendreau14-Nov-05 17:13 
GeneralRe: Some Useful CString extensions Pin
f28-Jul-06 3:47
f28-Jul-06 3:47 
GeneralRe: Some Useful CString extensions Pin
dgendreau10-Nov-06 12:06
dgendreau10-Nov-06 12:06 
QuestionUpdate to this class ? Pin
Defenestration2-Aug-05 23:57
Defenestration2-Aug-05 23:57 
AnswerRe: Update to this class ? Pin
soso_pub3-Aug-05 0:35
soso_pub3-Aug-05 0:35 
GeneralRe: Update to this class ? Pin
Defenestration4-Aug-05 6:46
Defenestration4-Aug-05 6:46 
GeneralRe: Update to this class ? Pin
soso_pub4-Aug-05 7:50
soso_pub4-Aug-05 7:50 
GeneralRe: Update to this class ? Pin
Avis p16-Aug-05 0:42
Avis p16-Aug-05 0:42 
GeneralUseful Link Pin
Feroz_Zahid6-Jul-04 19:41
Feroz_Zahid6-Jul-04 19:41 
QuestionExtractSubstring function? Pin
Andrei Keino10-Jun-04 21:42
Andrei Keino10-Jun-04 21:42 
Generalwindows-centric Pin
Member 1081419018-Aug-03 4:48
Member 1081419018-Aug-03 4:48 
GeneralFound something really... Pin
Kochise16-Jul-03 3:31
Kochise16-Jul-03 3:31 
GeneralAnother one... Pin
Kochise16-Jul-03 3:37
Kochise16-Jul-03 3:37 
QuestionCould this be a problem? Pin
John Vilburn8-Jul-03 4:34
John Vilburn8-Jul-03 4:34 
AnswerRe: Could this be a problem? Pin
soso_pub8-Jul-03 6:36
soso_pub8-Jul-03 6:36 
GeneralOK, now everybody just STOPS complaining ! Pin
Kochise2-Jul-03 2:13
Kochise2-Jul-03 2:13 
GeneralRe: OK, now everybody just STOPS complaining ! Pin
jhwurmbach2-Jul-03 2:45
jhwurmbach2-Jul-03 2:45 
GeneralFair... Pin
Kochise2-Jul-03 2:54
Kochise2-Jul-03 2:54 
GeneralRe: Fair... Pin
jhwurmbach2-Jul-03 3:35
jhwurmbach2-Jul-03 3:35 
Kochise wrote:
In Cod we trust !

Isn't that the fish in fish-n-chips? And you trust in something like THAT? Poke tongue | ;-P

My application involves operation on spectra, and these can get amazingly big: a few hundred MB are not unusual.
But even with that, only a small portion of the application is really speed sensitive, and most of that are numeric algorithms totally without MFC. Using a design which tries not to copy the data does more speedup than optimizing the algorithms (which I don't understand anyway Wink | ;) )

Within the GUI, it does not matter if writing an XML file could be an order of magnitude faster using char* and legacy C string-routines.
The writing goes to a disk file, and that forms the bottleneck.

With your SuperGrid example, I would say that using a callback approach instead of copying the data into the grid would improve speed sufficiently. Most of the time using different algorithms is much easier than optimizing existing ones.




My opinions may have changed, but not the fact that I am right.
GeneralOK, here something for you, unfaithful one ! Pin
Kochise2-Jul-03 4:45
Kochise2-Jul-03 4:45 
GeneralRe: OK, here something for you, unfaithful one ! Pin
soso_pub2-Jul-03 5:27
soso_pub2-Jul-03 5:27 
GeneralI'm awaiting for the update right now... Pin
Kochise2-Jul-03 5:33
Kochise2-Jul-03 5:33 
GeneralRe: OK, here something for you, unfaithful one ! Pin
Max Santos26-Mar-06 7:45
Max Santos26-Mar-06 7:45 
GeneralCStr is NOT faster than CString or std:string Pin
Defenestration5-Aug-07 12:51
Defenestration5-Aug-07 12:51 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.