[comp.lang.c++] Getting a string class to work.

anthes@geocub.greco-prog.fr (Franklin Anthes) (03/20/90)

I'm just starting out with C++. I want to build a very basic String
class. 

BTW I wonder why such basic classes as String, etc. standard in C++?
It is a good idea of course to do something like this once or twice during
the learning process, but reinventing each wheel can become tedious after
a while.

Anyway, here's a small piece of my code :

typedef unsigned long StringLenType;

class String {
        char *buf;
        StringLenType len;
public:
        String();
        String(const char *);
        String(const String &);
        ~String();
        String& operator=(const String&);
        friend String& operator+(String&,String&);
}

String& String::operator=(const String& s) {
        len = s.len;
        delete buf;
        buf = new char[len+1];
        strcpy(buf,s.buf);
        return *this;
}

String& operator+(String& s1,String& s2) {
        String*& ret = new String( s1.len + s2.len );
        memcpy(ret->buf,s1.buf,s1.len);
        memcpy(ret->buf+s1.len,s2.buf,s2.len+1);
        return *ret;
}

I want to implement operations like :

 String s1;
 String s2("foo");
 String s3("bar");

 s1 = s2 + s3; // s1 == "foobar"

Now the code above "works", but the space allocated by operator+ is not
deleted. Is there an elegant way to do this sort of thing in C++?

A possible solution (kludge) would be to add a tag into the String class,
to indicate whether the string is a temporary which should be deleted after
the result is calculated. Hmm garbage collection can come in handy sometimes.

A big merci, for those willing to help me me out.
-- 

	Frank Anthes-Harper :  Bien le bonjour de la France
	anthes@geocub.greco-prog.fr

ark@alice.UUCP (Andrew Koenig) (03/23/90)

In article <1760@geocub.greco-prog.fr>, anthes@geocub.greco-prog.fr (Franklin Anthes) writes:

> typedef unsigned long StringLenType;

> class String {
>         char *buf;
>         StringLenType len;
> public:
>         String();
>         String(const char *);
>         String(const String &);
>         ~String();
>         String& operator=(const String&);
>         friend String& operator+(String&,String&);
> }

operator+ should probably take const String& arguments and return
a String result, not a String&.

In order to return a String&, there has to be some pre-existing
String to which to bind the reference.  Since the purpose of
operator+ is to create a new String, it is hardly likely that
an appropriate String exists.  So, without reading further,
I would change the declaration to

	friend String operator+(const String&, const String&);

> String& String::operator=(const String& s) {
>         len = s.len;
>         delete buf;
>         buf = new char[len+1];
>         strcpy(buf,s.buf);
>         return *this;
> }

Almost right.  This fails if you assign a String to itself, though.
Try it this way:

String& String::operator=(const String& s) {
	char* newbuf = new char[len+1];
        len = s.len;
        strcpy(newbuf,s.buf);
	delete buf;
	buf = newbuf;
        return *this;
}

> String& operator+(String& s1,String& s2) {
>         String*& ret = new String( s1.len + s2.len );
>         memcpy(ret->buf,s1.buf,s1.len);
>         memcpy(ret->buf+s1.len,s2.buf,s2.len+1);
>         return *ret;
> }

Oops!  You allocated memory for `ret' but never freed it,
as I suggested earlier might happen.  Also, I don't understand
how `new String(s1.len + s2.len)' can work unless you have
String(int) defined to allocate that much memory, which doesn't
appear in your declaration.  Try it this way:

String operator+(const String& s1,const String& s2) {
        String ret;
	ret.buf = new char[s1.len + s2.len + 1];
        memcpy(ret.buf,s1.buf,s1.len);
        memcpy(ret.buf+s1.len,s2.buf,s2.len+1);
        return ret;
}

For this to work, you must have defined String(const String&) correctly.
For example:

String::String(const String& s) {
	buf = new char[s.len + 1];
	memcpy(buf,s.buf,s.len+1);
	len = s.len;
}

> Now the code above "works", but the space allocated by operator+ is not
> deleted. Is there an elegant way to do this sort of thing in C++?

The strategy outlined above should avoid all memory leaks.
-- 
				--Andrew Koenig
				  ark@europa.att.com