Faster than STL string class?

Y

YinTat

Hi,
I learned C++ recently and I made a string class.
A code example is this:

class CString
{
public:
inline CString(const char *rhs)
{
m_size = strlen(rhs);
m_capacity = m_size * 2 + 1;
m_str = new char[m_capacity];
memmove(m_str, rhs, m_size+1);
}

inline CString& __cdecl operator+= (const CString& rhs)
{
unsigned __int32 tmp_size = m_size + rhs.m_size;

if (m_capacity <= tmp_size)
{
m_capacity = tmp_size * 2 + 1;
char *tmp_char = new char[m_capacity];
memmove(tmp_char, m_str, m_size);
delete m_str;
m_str = tmp_char;
}

memmove(m_str+m_size, rhs.m_str, rhs.m_size);
m_size = tmp_size;
return *this;
}
private:
char *m_str;
unsigned __int32 m_capacity;
unsigned __int32 m_size;
};


//stl string class
string tmp1 = "123123";
string tmp2 = "999999";
for(int i=0;i<50000;++i)
tmp1 += tmp2;
//1936033.000000 microsecond

//the "CString" class
CString tmp1 = "123123";
CString tmp2 = "999999";
for(int i=0;i<50000;++i)
tmp1 += tmp2;
//21106.333333 microsecond

Have any bug or harmful code in the "CString" class?
Why the "CString" class faster than STL string class?
Many books said that "You should not develop a class that have been developed"
In this case, Which is better?
Who can help me make a choice?

Regards,
YinTat
 
R

Rolf Magnus

YinTat wrote:


My results are different:
//stl string class
string tmp1 = "123123";
string tmp2 = "999999";
for(int i=0;i<50000;++i)
        tmp1 += tmp2;
//1936033.000000 microsecond

9780 microseconds
//the "CString" class
CString tmp1 = "123123";
CString tmp2 = "999999";
for(int i=0;i<50000;++i)
tmp1 += tmp2;
//21106.333333 microsecond

4147 microseconds

I wonder why string handling is so horribly slow on your system, or was
that on some embedded system or very old PC?
Still, yours is quite a bit faster than the standard string, but the
question is how closely your "benchmark" resembles the typical use of
strings.
Have any bug or harmful code in the "CString" class?

It is not thread safe.
 
T

Thomas Matthews

YinTat said:
Hi,
I learned C++ recently and I made a string class.
A code example is this:

class CString
{ [snip]
};
[snip]

By the way, the Microsoft Compiler already has a class called
CString.

Should the name be changed to CppString?
A "C" string generally refers to a null terminated array
of characters; which is a string in the C language sense.

See:
http://www.jelovic.com/articles/stupid_naming.htm
Regards,
YinTat


--
Thomas Matthews

C++ newsgroup welcome message:
http://www.slack.net/~shiva/welcome.txt
C++ Faq: http://www.parashift.com/c++-faq-lite
C Faq: http://www.eskimo.com/~scs/c-faq/top.html
alt.comp.lang.learn.c-c++ faq:
http://www.raos.demon.uk/acllc-c++/faq.html
Other sites:
http://www.josuttis.com -- C++ STL Library book
 
K

Kai-Uwe Bux

Rolf said:
YinTat wrote:


My results are different:


9780 microseconds

4147 microseconds

I wonder why string handling is so horribly slow on your system, or was
that on some embedded system or very old PC?
Still, yours is quite a bit faster than the standard string, but the
question is how closely your "benchmark" resembles the typical use of
strings.


It is not thread safe.


It appears as if the std::string class from the OP suffers from a O(n^2)
flaw that was hurting, e.g., some older version of MFC CString
implementations. This has been fixed, though.

On my machine the handcoded CString class beats std::string but not by a
factor of 2. However, it should be pointed out, that there is an obvious
parameter in the speed-space tradeoff: CString doubles the allocated
memory. It would surely waste less memory at the cost of more allocations
if that factor was decreased. Similarly, one could still speed it up by
increasing that factor.

Moreover, on many implementations, std::string is trying to be smart about
assignments. In reference count based implementations, many times an
assignment of strings will result in only little more than a pointer copy.
Thus, which implementation is better for a given project is very hard to
predict. In any case, I would doubt that the gain is worth the effort of
actually coding a complete string class. Well, unless of course std::string
completely sucks as appears to be the case with the OP.


Best

Kai-Uwe
 
G

Gernot Frisch

It is not thread safe.

Silly question: why? I don't get all this thread safe, multithreading
things. Can anyone explain it briefly?
-Gernot
 
V

Victor Bazarov

YinTat said:
I learned C++ recently and I made a string class.
A code example is this:

class CString
{
public:
inline CString(const char *rhs)
{
m_size = strlen(rhs);
m_capacity = m_size * 2 + 1;
m_str = new char[m_capacity];
memmove(m_str, rhs, m_size+1);
}

inline CString& __cdecl operator+= (const CString& rhs)
{
unsigned __int32 tmp_size = m_size + rhs.m_size;

if (m_capacity <= tmp_size)
{
m_capacity = tmp_size * 2 + 1;
char *tmp_char = new char[m_capacity];
memmove(tmp_char, m_str, m_size);
delete m_str;

delete[] m_str;
m_str = tmp_char;
}

memmove(m_str+m_size, rhs.m_str, rhs.m_size);
m_size = tmp_size;
return *this;
}
private:
char *m_str;
unsigned __int32 m_capacity;
unsigned __int32 m_size;
};


//stl string class
string tmp1 = "123123";
string tmp2 = "999999";
for(int i=0;i<50000;++i)
tmp1 += tmp2;
//1936033.000000 microsecond

//the "CString" class
CString tmp1 = "123123";
CString tmp2 = "999999";
for(int i=0;i<50000;++i)
tmp1 += tmp2;
//21106.333333 microsecond

Have any bug or harmful code in the "CString" class?

Well, it's not supposed to compile with a conforming compiler because
__cdecl and __int32 are not defined. I presume they are something
like
#define __cdecl
and
typedef long __int32;
in reality.

As to the bugs, yes, most definitely. First, see above. You use
'delete' where you supposed to use 'delete[]'. Second, your class
has a memory leak: the allocated memory is never released if the
string doesn't have to grow, and even then, the first one is freed
when the second allocated, but there is always one array that is
never released at the end. It may be acceptable to you, but it's
definitely unacceptable in a standard library implementation.
Why the "CString" class faster than STL string class?

Because it has very little functionality and is buggy. Analogy:
a race car can go faster than a production car or go over a rougher
terrain, but it can never compare with the production car in comfort,
universality, gas mileage, etc.

Remove all the glass from your car, remove the spare tire, drop the
back seat, the passenger seat, reduce the gas tank to one gallon,
replace the hood, the quarter-panels, door panes, with plastic, and
you will have something that drives faster than it did before all
the modifications. Is it better? Depends on how you look at it.
Many books said that "You should not develop a class that have been developed"
In this case, Which is better?

Better is the one that is bug-free. Once you make your class bug-
free, your class can still be better in some applications (i.e. for
doing what you need it to do), but it can never be as suitable for
being in a library as the one in the library.
Who can help me make a choice?

Wise people that write books can. If you don't listen to them, or
to those who give you advice elsewhere, how can they help you make
your choice?

Some folks I've known have developed their own custom string types
for very specific purposes. Those string classes are fast and slim
but can only be used in a very limited set of conditions. The string
class in the Standard Library is designed with a different purpose.
It's generic, it's conforming to requirements to standard containers,
it's stable, and it's portable. If you don't like it, or if you have
other requirements (fewer, less strict, whatever), and you have enough
time to spare, do design your own, by all means. Just please do not
put such class in an application running on a life support machine to
which I'm going to be hooked up after a major surgery.

V
 
J

Julie

Gernot said:
Silly question: why? I don't get all this thread safe, multithreading
things. Can anyone explain it briefly?
-Gernot

In the context of the C++ language, it doesn't matter and is actually
off-topic.

Unless you are using operating-system specific calls, a C++ program has no
notion of threads, multi-threadedness, etc. and doesn't need to be considered
when writing code.

If you are using threads, then you need to refer to the specifics of that
implementation as to how it affects the C++ libraries.

In short, you don't need to worry about it unless you specifically use threads.

However, in answer to your question: thread-safe describes some construct,
class, etc. that is specifically protected against corruption if two (or more)
threads try to access that object at the same time. For example, suppose you
have one string 'str' and two threads and perform the following:

//thread 1
str = "hello from Earth";

// thread 2
str = "greetings to all inhabitants of Mars";

If both were executed simultaneously, what would be the outcome? If str isn't
thread-safe, corruption would be inevitable. If str is thread-safe, then
typically the first thread to write would be granted exclusive write-access
until the assignment is completed, and the second thread would block until the
first is done, and then would gain exclusive write access.

Books are devoted to the subject, this is a trivial example, but should serve
to answer your question.
 
R

Ron Samuel Klatchko

class CString
{
public:
inline CString(const char *rhs)
{
m_size = strlen(rhs);
m_capacity = m_size * 2 + 1;
m_str = new char[m_capacity];
memmove(m_str, rhs, m_size+1);
}

inline CString& __cdecl operator+= (const CString& rhs)
{
unsigned __int32 tmp_size = m_size + rhs.m_size;

if (m_capacity <= tmp_size)
{
m_capacity = tmp_size * 2 + 1;
char *tmp_char = new char[m_capacity];
memmove(tmp_char, m_str, m_size);
delete m_str;
m_str = tmp_char;
}

memmove(m_str+m_size, rhs.m_str, rhs.m_size);
m_size = tmp_size;
return *this;
}
private:
char *m_str;
unsigned __int32 m_capacity;
unsigned __int32 m_size;
};

Have any bug or harmful code in the "CString" class?

I see two problems with this code:

1) No destructor.
2) Not exception safe. If new throws in operator+=, m_capacity will have
a larger value then the actual capacity. If you call operator+= after
catching an exception, the code can write to memory it does not own.]

samuel
 
M

Martin M. Pedersen

YinTat said:
Have any bug or harmful code in the "CString" class?
Why the "CString" class faster than STL string class?

Besides the problems already mentioned, you are missing a destructor, copy
constructor and copy assignment.

Regards,
Martin
 
D

Daniel T.

Hi,
I learned C++ recently and I made a string class.

I would respectfully suggest that someone who recently learned C++, may
not be the best person to decide that they can write a better string
class than multi-year professionals.

A code example is this:

class CString
{
public:
inline CString(const char *rhs)
{
m_size = strlen(rhs);
m_capacity = m_size * 2 + 1;

Why are you adding one here?
m_str = new char[m_capacity];
memmove(m_str, rhs, m_size+1);

I see that you are copying the null into m_str here...

You need a copy c_tor and d_tor or everytime you are done using a
CString, you will be leaking memory, and everytime you copy one CString
to another, you will be both leaking memory and making it impossible for
the two CString objects to work properly.

inline CString& __cdecl operator+= (const CString& rhs)
{
unsigned __int32 tmp_size = m_size + rhs.m_size;

if (m_capacity <= tmp_size)
{
m_capacity = tmp_size * 2 + 1;

Again, your adding one. Why?
char *tmp_char = new char[m_capacity];

If new throws, m_capacity will equal the wrong value.
memmove(tmp_char, m_str, m_size);
delete m_str;

That's delete [] m_str;
m_str = tmp_char;
}

memmove(m_str+m_size, rhs.m_str, rhs.m_size);

Here you don't copy the null into m_str like you did above. Why?
m_size = tmp_size;
return *this;
}
private:
char *m_str;
unsigned __int32 m_capacity;
unsigned __int32 m_size;
};
Have any bug or harmful code in the "CString" class?

CString s1( "hello" );
CString s2( "world" );
s1 = s2;
s1 += s1;
// now look at the contents of s2...

while (true) {
CString s1( "abcdefghijklmnopqrstuvwxyz" );
}

While the above is running track your programs memory usage...

Why the "CString" class faster than STL string class?

Because your CString class doesn't do everything std::string does. Your
CString class is designed more like a std::vector<char>. Compare your
CString to that and see what happens. (Make sure you are compiling in
debug mode when you do this.)

Many books said that "You should not develop a class that have been developed"

Why do you think they say that?

In this case, Which is better?

(1) The one that works.
(2) If (and only if) they both work, then use the one that is more
efficient for the task at hand. In some cases a class like yours (that
routenly holds twice as much memory as needed,) would be a very bad
choice; in some cases any class that requires the memory be contigious
would be a bad choice. Use the one that best solves your particular
problem.


You may very well be able to implement a better string class than the
one that comes with your library. If you can, then more power to you!
Implementing std::string is one of the many worthy projects for a
beginner learning the language (though implementing std::vector would be
easier.)
 
S

Siemel Naran

Ron Samuel Klatchko said:
I see two problems with this code:

1) No destructor.
2) Not exception safe. If new throws in operator+=, m_capacity will have
a larger value then the actual capacity. If you call operator+= after
catching an exception, the code can write to memory it does not own.]

Right, I have found that calls to delete and delete[] are often quite
expensive.

You can often gain strong exception safety by rearranging code, rather than
by using try-catch blocks.
 
B

Branimir Maksimovic

YinTat said:
Hi,
I learned C++ recently and I made a string class.

In addition to others in this thread, I can add some comments.
A code example is this:

class CString
{
public:
inline CString(const char *rhs)
{
m_size = strlen(rhs);
m_capacity = m_size * 2 + 1;
m_str = new char[m_capacity];
memmove(m_str, rhs, m_size+1);

Here you copy terminating zero into CString.
}

inline CString& __cdecl operator+= (const CString& rhs)
{
unsigned __int32 tmp_size = m_size + rhs.m_size;

if (m_capacity <= tmp_size)
{
m_capacity = tmp_size * 2 + 1;
char *tmp_char = new char[m_capacity];
memmove(tmp_char, m_str, m_size);
delete m_str;
m_str = tmp_char;
}

memmove(m_str+m_size, rhs.m_str, rhs.m_size);
m_size = tmp_size;
return *this;
}


no terminating zero in this case
Why the "CString" class faster than STL string class?
Not on my system:)
I think that's probably because of allocation strategy.
int main()
{
clock_t start = clock();
//stl string class
string tmp1;
tmp1.reserve(500001*6);
tmp1 = "123123";
string tmp2 = "999999";
for(int i=0;i<500000;++i)
{
tmp1 += tmp2;
}
clock_t end = clock();
cout<<"string:"<<(end-start)<<'\n';
//1936033.000000 microsecond

//the "CString" class
start = clock();
CString ctmp1 = "123123";
CString ctmp2 = "999999";
for(int i=0;i<500000;++i)
{
ctmp1 += ctmp2;
}
end = clock();
cout<<"cstring:"<<(end-start)<<'\n';
//21106.333333 microsecond

}

[bmaxa@localhost bmaxa]$ g++ -O3 -Wall faster.cc -o faster
[bmaxa@localhost bmaxa]$ ./faster
string:50000
cstring:40000
[bmaxa@localhost bmaxa]$ ./faster
string:50000
cstring:50000
[bmaxa@localhost bmaxa]$ ./faster
string:50000
cstring:40000
[bmaxa@localhost bmaxa]$ ./faster
string:40000
cstring:40000
[bmaxa@localhost bmaxa]$ ./faster
string:50000
cstring:40000
[bmaxa@localhost bmaxa]$ ./faster
string:50000
cstring:40000
[bmaxa@localhost bmaxa]$ ./faster
string:50000
cstring:50000
[bmaxa@localhost bmaxa]$ ./faster
string:50000
cstring:40000
[bmaxa@localhost bmaxa]$ ./faster
string:50000
cstring:40000
[bmaxa@localhost bmaxa]$ ./faster
string:40000
cstring:50000


Greets, Bane.
 
Y

YinTat

Martin M. Pedersen said:
Besides the problems already mentioned, you are missing a destructor, copy
constructor and copy assignment.

Regards,
Martin

#pragma once

#include <cstring>
/************************************Class*************************************/
class CString
{
public:
/***********************Construction/Destruction***************************/
inline CString():m_capacity(1), m_size(0)
{
m_str = new char[1];
}

inline CString(const CString& rhs)
{
m_size = rhs.m_size;
m_capacity = rhs.m_capacity;
m_str = new char[m_capacity];
memmove(m_str, rhs.m_str, m_size+1);
}

inline CString(const char *rhs)
{
m_size = strlen(rhs);
m_capacity = m_size * 2 + 1;
m_str = new char[m_capacity];
memmove(m_str, rhs, m_size+1);
}

inline ~CString()
{
delete[] m_str;
}
/*******************************Operator***********************************/
inline CString& operator= (const CString& rhs)
{
if (this == &rhs)
return *this;

m_size = rhs.m_size;

if (m_capacity <= m_size)
{
m_capacity = rhs.m_capacity;
delete[] m_str;
m_str = new char[m_capacity];
}

memmove(m_str, rhs.m_str, m_size+1);
return *this;
}

inline CString& operator= (const char *rhs)
{
if (m_str == rhs)
return *this;

m_size = strlen(rhs);

if (m_capacity <= m_size)
{
m_capacity = m_size * 2 + 1;
delete[] m_str;
m_str = new char[m_capacity];
}

memmove(m_str, rhs, m_size+1);
return *this;
}

inline bool operator== (const CString& rhs)
{
if (m_size == rhs.m_size)
return (memcmp(m_str, rhs.m_str, m_size)==0);
else
return false;
}

inline bool operator== (const char *rhs)
{
return (memcmp(m_str, rhs, m_size)==0);
}

inline CString& operator+= (const CString& rhs)
{
unsigned int tmp_size = m_size + rhs.m_size;

if (m_capacity <= tmp_size)
{
m_capacity = tmp_size * 2 + 1;
char *tmp_char = new char[m_capacity];
memmove(tmp_char, m_str, m_size);
delete[] m_str;
m_str = tmp_char;
}

memmove(m_str+m_size, rhs.m_str, rhs.m_size);
m_size = tmp_size;
return *this;
}

inline CString& operator+= (const char *rhs)
{
unsigned int rhs_size = strlen(rhs);
unsigned int tmp_size = m_size + rhs_size;

if (m_capacity <= tmp_size)
{
m_capacity = tmp_size * 2 + 1;
char *tmp_char = new char[m_capacity];
memmove(tmp_char, m_str, m_size);
delete[] m_str;
m_str = tmp_char;
}

memmove(m_str+m_size, rhs, rhs_size);
m_size = tmp_size;
return *this;
}

inline CString* operator& ()
{
return this;
}

inline const CString* operator& () const
{
return this;
}
/****************************Class
Function********************************/
//"123456789".size = "123456789"
inline const char* c_str()
{
return m_str;
}
//"123456789".size = 9
inline unsigned int size()
{
return m_size;
}
//"123456789".clearmem = ""
inline CString& clearmem()
{
delete[] m_str;
m_str = new char[1];
m_capacity = 1;
m_size = 0;
return *this;
}
//"123456789".insert(3,"xxx")="123xxx456789"
inline CString& insert(unsigned int pos, const char *rhs)
{
unsigned int rhs_size = strlen(rhs);
unsigned int tmp_size = m_size + rhs_size;

if (m_capacity <= tmp_size)
{
m_capacity = tmp_size * 2 + 1;
char *tmp_char = new char[m_capacity];
memmove(tmp_char, m_str, pos);
memmove(tmp_char+pos+rhs_size, m_str+pos, m_size-pos+1); //1 for
'/0'
delete[] m_str;
m_str = tmp_char;
}
else
{
memmove(m_str+pos+rhs_size, m_str+pos, m_size-pos+1);
}

memmove(m_str+pos, rhs, rhs_size);
m_size = tmp_size;
return *this;
}
//"123456789".insert(3,"xxx")="123xxx456789"
inline CString& insert(unsigned int pos, const CString& rhs)
{
unsigned int tmp_size = m_size + rhs.m_size;

if (m_capacity <= tmp_size)
{
m_capacity = tmp_size * 2 + 1;
char *tmp_char = new char[m_capacity];
memmove(tmp_char, m_str, pos);
memmove(tmp_char+pos+rhs.m_size, m_str+pos, m_size-pos+1);//1 for
'/0'
delete[] m_str;
m_str = tmp_char;
}
else
{
memmove(m_str+pos+rhs.m_size, m_str+pos, m_size-pos+1);
}

memmove(m_str+pos, rhs.m_str, rhs.m_size);
m_size = tmp_size;
return *this;
}
//"123456789".erase(3,3)="123789"
inline CString& erase(unsigned int pos, unsigned int len)
{
memmove(m_str+pos, m_str+pos+len, m_size-pos+1);
m_size = m_size - len;
return *this;
}
//"123456789".assign(3,3)="456"
inline CString& assign(unsigned int pos, unsigned int len)
{
memmove(m_str, m_str+pos, len);
m_str[len] = '\0';
m_size = len;
return *this;
}
//"123456789".fill(5,'1') = "11111"
inline CString& fill(unsigned int len, char fillch)
{
if (m_capacity <= m_size)
{
m_capacity = len * 2 + 1;
delete[] m_str;
m_str = new char[m_capacity];
}
memset(m_str, fillch, len);
m_str[len] = '0';
return *this;

}
//"123456789".replace(3,3,"xxxxxx") = "123xxxxxx789"
inline CString& replace(unsigned int pos, unsigned int len,
const char *rhs)
{
if ((pos + len) > m_size)
throw 0xC000008CL;
unsigned int rhs_size = strlen(rhs);
unsigned int tmp_size = m_size + rhs_size - len;

if (len != rhs_size)
{
if (m_capacity <= tmp_size)
{
m_capacity = tmp_size * 2 + 1;
char *tmp_char = new char[m_capacity];
memmove(tmp_char, m_str, pos);
memmove(tmp_char+pos+rhs_size, m_str+pos+len,
tmp_size-pos-rhs_size+1); //1 for '/0'
delete[] m_str;
m_str = tmp_char;
}
else
{
memmove(m_str+pos+rhs_size, m_str+pos+len,
tmp_size-pos-rhs_size+1); //1 for '/0'
}
}

memmove(m_str+pos, rhs, rhs_size);
m_size = tmp_size;
return *this;
}
//"123456789".replace(3,3,"xxxxxx") = "123xxxxxx789"
inline CString& replace(unsigned int pos, unsigned int len,
CString& rhs)
{
if ((pos + len) > m_size)
throw 0xC000008CL;
unsigned int tmp_size = m_size + rhs.m_size - len;

if (len != rhs.m_size)
{
if (m_capacity <= tmp_size)
{
m_capacity = tmp_size * 2 + 1;
char *tmp_char = new char[m_capacity];
memmove(tmp_char, m_str, pos);
memmove(tmp_char+pos+rhs.m_size, m_str+pos+len,
tmp_size-pos-rhs.m_size+1); //1 for '/0'
delete[] m_str;
m_str = tmp_char;
}
else
{
memmove(m_str+pos+rhs.m_size, m_str+pos+len,
tmp_size-pos-rhs.m_size+1); //1 for '/0'
}
}

memmove(m_str+pos, rhs.m_str, rhs.m_size);
m_size = tmp_size;
return *this;
}
private:
char *m_str;
unsigned int m_capacity;
unsigned int m_size;
};
 
M

Mats Weber

Have any bug or harmful code in the "CString" class?

It is not thread safe.[/QUOTE]

I don't see what makes the OP's CString less thread safe than
std::string. Can you clarify ?
 
R

Rolf Magnus

Mats said:
It is not thread safe.

I don't see what makes the OP's CString less thread safe than
std::string. Can you clarify ?[/QUOTE]

For std::string, it depends on the implementation. The OP's
implemenatation of his class definitely isn't thread safe.
 
P

Peter van Merkerk

Mats Weber said:
It is not thread safe.

I don't see what makes the OP's CString less thread safe than
std::string. Can you clarify ?[/QUOTE]

The m_capacity member is updated before new char[...]. If the new operator
throws an exception the CString object is left in an invalid state;
m_capacity member holds a value that does not reflect the actual size of
the allocated buffer.
 
J

Julie

Peter said:
Mats Weber said:
I don't see what makes the OP's CString less thread safe than
std::string. Can you clarify ?

The m_capacity member is updated before new char[...]. If the new operator
throws an exception the CString object is left in an invalid state;
m_capacity member holds a value that does not reflect the actual size of
the allocated buffer.

You are talking about exception safe, which has nothing to do w/ threads or
thread-safe.
 
M

Mats Weber

Peter van Merkerk said:
The m_capacity member is updated before new char[...]. If the new operator
throws an exception the CString object is left in an invalid state;
m_capacity member holds a value that does not reflect the actual size of
the allocated buffer.

That is exception safety, not thread safety.
 
M

Mats Weber

Rolf Magnus said:
For std::string, it depends on the implementation. The OP's
implemenatation of his class definitely isn't thread safe.

You really have to define what you mean by thread safe for a string
handling package. If you mean that two threads should be able to
concurrently access the same string object, then I think no reasonable
implementation of std::string will do that because the overhead would be
HUGE.

If you just mean that distinct strings can be manipulated concurrently,
then the OP's implementation is just fine because it has no global
variable. The only global resource is memory, and thread safe versions
of new/delete are used in a threaded program.
 
Y

YinTat

I would respectfully suggest that someone who recently learned C++, may
not be the best person to decide that they can write a better string
class than multi-year professionals.
So I very worry that I will regret...
Why are you adding one here?
I also don't know why I adding one here...
I adding one here by "intuition" =="
m_str = new char[m_capacity];
memmove(m_str, rhs, m_size+1);

I see that you are copying the null into m_str here...

You need a copy c_tor and d_tor or everytime you are done using a
CString, you will be leaking memory, and everytime you copy one CString
to another, you will be both leaking memory and making it impossible for
the two CString objects to work properly.

inline CString& __cdecl operator+= (const CString& rhs)
{
unsigned __int32 tmp_size = m_size + rhs.m_size;

if (m_capacity <= tmp_size)
{
m_capacity = tmp_size * 2 + 1;

Again, your adding one. Why?
char *tmp_char = new char[m_capacity];

If new throws, m_capacity will equal the wrong value.
memmove(tmp_char, m_str, m_size);
delete m_str;

That's delete [] m_str;
In destruction, I use "delete [] m_str;"....
but I forget adding "[]" in here...
thanks!
Here you don't copy the null into m_str like you did above. Why?
I forget once again.....
Thanks..
I have no remembrance and experience.
CString s1( "hello" );
CString s2( "world" );
s1 = s2;
s1 += s1;
// now look at the contents of s2...

while (true) {
CString s1( "abcdefghijklmnopqrstuvwxyz" );
}

While the above is running track your programs memory usage...



Because your CString class doesn't do everything std::string does. Your
CString class is designed more like a std::vector<char>. Compare your
CString to that and see what happens. (Make sure you are compiling in
debug mode when you do this.)
But in my compiler(VC++6) std::string is designed like a
std::vector<char>.
(doubles the allocated memory)
So I was disorientated....
Why do you think they say that?



(1) The one that works.
(2) If (and only if) they both work, then use the one that is more
efficient for the task at hand. In some cases a class like yours (that
routenly holds twice as much memory as needed,) would be a very bad
choice; in some cases any class that requires the memory be contigious
would be a bad choice. Use the one that best solves your particular
problem.
My case is a ISAPI extension, and therefore I very attach importance
to string class.
You may very well be able to implement a better string class than the
one that comes with your library. If you can, then more power to you!
Implementing std::string is one of the many worthy projects for a
beginner learning the language (though implementing std::vector would be
easier.)
So, I am making std::vector,std::list,std::vector_list,std::exception
and database class.
Has Anything else good for beginner?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,754
Messages
2,569,525
Members
44,997
Latest member
mileyka

Latest Threads

Top