Axter wrote:

[snip]

I've reread you're previous post on this subject, but I don't see where

you're giving a valid reason why Herb Sutters recommend method should

not be recommended as a general rule.

Right. I just gave examples where it might be better/easier to go the other

way. Given the closing remark of your current posting, I see now that I was

reading too much into the recommendation. Sorry.

However, in the course of this conversation, I have been thinking about this

issue more carefully; and now I feel prepared to actually provide a reason

why the general recommendation should be to define

[email protected]= in terms of

[email protected] and operator=. I think it is less error prone than the

Sutter/Alexandrescu way.

The example of the OP can be used to illustrate this. Let us have a look at

a rational number class:

class rational {

long n; // numerator

long d; // denominator

public:

// ... stuff

};

Ignoring reduction to lowest possible terms, the Sutter/Alexandrescu way to

go about addition is:

rational & operator+= ( rational & lhs, rational const & rhs ) {

lhs.n = lhs.n * rhs.d + lhs.d * rhs.n;

lhs.d *= rhs.d;

return ( lhs );

}

rational operator+ ( rational const & lhs, rational const & rhs ) {

rational result ( lhs );

result += rhs;

return ( result );

}

This is easy to get wrong:

rational & operator+= ( rational & lhs, rational const & rhs ) {

lhs.d *= rhs.d;

lhs.n = lhs.n * rhs.d + lhs.d * rhs.n; // wrong: uses new lhs.d !

}

The archives show posts dealing with re-implementations of std::complex that

suffer from this kind of bug. And I myself found myself recently falling

for this while working on a matrix class (maybe that is why I am so

sensitive to this issue right now): I was using entries that I had just

overwritten.

On the other hand,

rational operator+ ( rational const & lhs, rational const & rhs ) {

rational result ( lhs.n * rhs.d + lhs.d * rhs.n, lhs.d * rhs.d );

return result;

}

rational & operator+= ( rational & lhs, rational const & rhs ) {

lhs = lhs + rhs;

return ( lhs );

}

is much less prone to this kind of bug. (Come to think of it, this might be

the reason that Sutter and Alexandrescu mention the complex number class as

a case where they would recommend the second approach.)

Your followup post suggested the opposite approach using swap method.

Actually, I wrote that in my first post on this topic. In my follow up, I

elaborated on expression templates.

But not all classes have swap method, and infact, most don't. Those

that do, don't always have an efficient swap method.

True, in that case, you would use assignment. I suggested the swap method

because of the examples that I mentioned: matrix multiplication and

arbitrary precission operations. In both cases, a swap method *should* be

there and more efficient than assignment.

I'm sure there are times when using the opposite approach would be more

efficient, but in general, I would recommend Herb Sutters method.

As far as efficiency is concerned, you are right. However, I would remark

that this optimizes

[email protected]= only:

[email protected] will not get any faster than

a direct implementation. Also, I would contend that expression templates

are yet more efficient to eliminate unwanted temporaries (altough the added

complexity to the code is considerable and for this reason I would not

recommend this as a general approach). Anyway, as a measure to optimize

performance, I would agree with you.

However, as a general guideline I would rather recommend the following

procedure:

1) First, write

[email protected]= in terms of

[email protected] and operator= because

that is the most easy version to get right.

2) If profiling shows a need for optimization, refactor

[email protected]=. Use

your

[email protected] code for inspiration.

3) Run tests to check whether the semantics agree. This should catch

bugs like the one above.

4) Finally rewrite

[email protected] following the Sutter/Alexandrescu approach.

This eliminates code dubblication.

The Sutter/Alexandrescu recommendation, to me, looks a little bit like

premature optimization.

Remember, that a general rule is for general purposes. It doesn't mean

that the rule is required to be followed for every requirement.

Thanks for reminding me. I tend to forget about caveats that always apply.

Best regards

Kai-Uwe Bux