Sign in to follow this  
DevFred

implementing operator+= in terms of operator= and operator+

Recommended Posts

I'm writing my own String class for educational purposes only, and I was wondering if this is legal C++:
class String
{
private:
    size_t len;
    char* p;

public:
    String(size_t len) : len(len), p(new char[len + 1])
    {
        p[len] = 0;
    }

    // ... lots of stuff left out ...

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

    String operator+(const String& s)
    {
        String r(len + s.len);
        strcpy(r.p, p);
        strcpy(r.p + len, s.p);
        return r;
    }

    String& operator+=(const String &s)
    {
        return *this = *this + s; // <--- can I do this? (no pun intended)
    }

    // ... lots of stuff left out ...
};


I'm just not sure if it's legal to change *this in a member function. Thanks!

Share this post


Link to post
Share on other sites
An alternative that might be better is to implement operator+ in terms of operator+=.

String operator+(const String& s) {
String temp(*this);

return temp += s;
}



And implement the actual functionality in +=.

Share this post


Link to post
Share on other sites
Yeah, you can do this. It is perfectly legal to change this in member function -- in fact, that's what member functions are there for.

However, more usual way is to make operator+ non-member and implement it by calling member operator+= which does the actual work.

Share this post


Link to post
Share on other sites
Quote:
Original post by Oxyd
However, more usual way is to make operator+ non-member and implement it by calling member operator+= which does the actual work.

OK, how about this?


class String
{
// ...
String& operator+=(const String &s)
{
int n = len + s.len;
char *q = new char[n + 1];
strcpy(q, p);
strcpy(q + len, s.p);
len = n;
delete[] p;
p = q;
return *this;
}
// ...
};

String operator+(const String &s, const String& t)
{
String r(s);
return r += t;
}

Share this post


Link to post
Share on other sites
Quote:
Original post by DevFred
Quote:
Original post by Oxyd
However, more usual way is to make operator+ non-member and implement it by calling member operator+= which does the actual work.

OK, how about this?

*** Source Snippet Removed ***


That is exactly what I meant. [wink]

Share this post


Link to post
Share on other sites
I would definitely normally implement operator + via a copy-construction and a call to operator +=. However, in this particular case, doing the reverse as you had originally is simpler and retains the same level of exception safety. So I say, use whichever you prefer in this instance.

Also, if you're interested in exception safety you might like to improve your assignment operator. At the moment, if the 'new' call throws an exception then the String will be left with p pointing to deleted memory, and the destructor of that object will then cause a nasty double-delete bug.

One such way to fix this would be like this:
    String& operator=(const String &s)
{
char *q = new char[s.len + 1];
strcpy(q, s.p);
delete[] p;
p = q;
len = s.len;
return *this;
}

Now if 'new' throws, then we're "happy as Larry" as the 'this' object doesn't get touched. Note also that because self-assignment also no longer causes a problem, there's no need to explicitly test for and avoid it. Self-assignment is extremely rare in practice so we needn't worry about the fact that it now does actually do copying in this case, and we can instead be pleased with the elimination of the if-statement.

Share this post


Link to post
Share on other sites
Quote:
Original post by iMalc
I would definitely normally implement operator + via a copy-construction and a call to operator +=. However, in this particular case, doing the reverse as you had originally is simpler and retains the same level of exception safety. So I say, use whichever you prefer in this instance.

Hm, in bothes cases some unnecessary temporaries were created, so I rewrote the class like this (len is now called n):


class String
{
// ...
friend String operator+
(const String& s, const String& t);
};

String operator+(const String& s, const String& t)
{
String r(s.n + t.n);
strcpy(r.p, s.p);
strcpy(r.p + s.n, t.p);
return r;
}



Thanks about the exception safety hints!

[Edited by - DevFred on May 10, 2008 6:12:46 AM]

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this