Overloading +=

T

trouble

Hi,

I have the following code, which is basically overloading + and += for
complex numbers. It works fine, but can someone tell me how to use the
overloaded + in the definition of += rather than write the function
from scratch?

Thanks,
Ciao.

//-----------------------------------------------------------------
inline Complex Complex::eek:perator + (const Complex &right) const
{
Complex myComplex( real() + right.real(), imag() + right.imag());
return ( myComplex );
}
//-----------------------------------------------------------------
inline const Complex & Complex::eek:perator += (const Complex &right)
{
m_dRe += right.real();
m_dIm += right.imag();
return ( *this );
}
//------------------------------------------------------------------
 
R

Ron Natalie

trouble said:
Hi,

I have the following code, which is basically overloading + and += for
complex numbers. It works fine, but can someone tell me how to use the
overloaded + in the definition of += rather than write the function
from scratch?

Well, you could write operator += as
Compex& Complex::eek:perator+=(const Complex& right) {
*this = *this + right;
}
You don't normally expect += to return a const reference.
 
T

Thore B. Karlsen

Hi,

I have the following code, which is basically overloading + and += for
complex numbers. It works fine, but can someone tell me how to use the
overloaded + in the definition of += rather than write the function
from scratch?

You normally want to do it the other way around, for efficiency reasons.
Try this:

inline Complex Complex::eek:perator+(Complex right) const
{
right += *this;
return right;
}

inline Complex &Complex::eek:perator+=(const Complex &right)
{
m_dRe += right.real();
m_dIm += right.imag();
return *this;
}
 
Ð

ÐÜÕñÓî

I think the best way is to change you design.
1. overloaded + operator should not be member function
2. you shoud use overloaded += function in + function


like this:
inline const Complex & Complex::eek:perator += (const Complex &right)
{
m_dRe += right.real();
m_dIm += right.imag();
return ( *this );
}
inline Complex operator + (const Complex & left, const Complex &right) const
{
Complex temp(left)
return temp += right;
}

----- Original Message -----
From: "trouble" <[email protected]>
Newsgroups: comp.lang.c++
Sent: Friday, October 17, 2003 8:50 AM
Subject: Overloading +=
 
T

trouble

Thore B. Karlsen said:
On 16 Oct 2003 17:50:09 -0700, (e-mail address removed) (trouble) wrote:

Try this:

inline Complex Complex::eek:perator+(Complex right) const
{
right += *this;
return right;
}

inline Complex &Complex::eek:perator+=(const Complex &right)
{
m_dRe += right.real();
m_dIm += right.imag();
return *this;
}


Thanks, that looks much better than mine. Well, I say mine... I
inherited it from someone and wanted to add some extra functionality
w/o re-writing their code. Sad to say, it's a terrible mess of struct
Complex, Class Complex and separating into real/imag. I'm trying to go
with Class, since it's C++ 'n' all.

You can probably tell I'm not much of a C++er. Hey, do you know if C++
already has a standard Complex.h with all the operators in already?
It's too late for this code, but when I write my own it'd be good to
know.

Ciao.
 
R

Risto Lankinen

ÐÜÕñÓî said:
I think the best way is to change you design.
1. overloaded + operator should not be member function
2. you shoud use overloaded += function in + function

like this:
inline const Complex & Complex::eek:perator += (const Complex &right)
{
m_dRe += right.real();
m_dIm += right.imag();
return ( *this );
}
inline Complex operator + (const Complex & left, const Complex &right) const
{
Complex temp(left)
return temp += right;
}

Why do you think implementing op+ using op+= is more
efficient than vice versa? To me it would seem to be the
other way 'round. Consider that in a typical program op+
is far more often used than op+= .

I would also consider making the op+= a non-member
function, too.

Cheers!

- Risto -
 
H

Harald Grossauer

trouble said:
Hi,

I have the following code, which is basically overloading + and += for
complex numbers. It works fine, but can someone tell me how to use the
overloaded + in the definition of += rather than write the function
from scratch?

Thanks,
Ciao.

//-----------------------------------------------------------------
inline Complex Complex::eek:perator + (const Complex &right) const
{
Complex myComplex( real() + right.real(), imag() + right.imag());
return ( myComplex );
}
//-----------------------------------------------------------------
inline const Complex & Complex::eek:perator += (const Complex &right)
{
m_dRe += right.real();
m_dIm += right.imag();
return ( *this );
}
//------------------------------------------------------------------

Why don't you simply use the Complex Template from the STL?
 
K

Karl Heinz Buchegger

Risto said:
Why do you think implementing op+ using op+= is more
efficient than vice versa?

Because for operator+ you need a temporary object.
For operator+= you don't need this temporary.

So if you implement += in terms of +, you implicitely
add the creation of a temporary to +=. And that comes
with some costs.
To me it would seem to be the
other way 'round. Consider that in a typical program op+
is far more often used than op+= .

That's not an issue most of the time. Functions like that
are inlined by any decent compiler.
I would also consider making the op+= a non-member
function, too.

Why?

--
Karl Heinz Buchegger, GASCAD GmbH
Teichstrasse 2
A-4595 Waldneukirchen
Tel ++43/7258/7545-0 Fax ++43/7258/7545-99
email: (e-mail address removed) Web: www.gascad.com

Fuer sehr grosse Werte von 2 gilt: 2 + 2 = 5
 
F

Frank Schmitt

You can probably tell I'm not much of a C++er. Hey, do you know if C++
already has a standard Complex.h with all the operators in already?
It's too late for this code, but when I write my own it'd be good to
know.

Yes, it's called std::complex, defined in <complex>. It's templated
with the type of scalar you want to use.

HTH & kind regards
frank
 
R

Risto Lankinen

Hi!

Karl Heinz Buchegger said:
Because for operator+ you need a temporary object.
For operator+= you don't need this temporary.

So if you implement += in terms of +, you implicitely
add the creation of a temporary to +=. And that comes
with some costs.

Ah, now I see. For "simple" objects this may well be
a good heuristic, but for more complex (not Complex :)
objects you will run into problems with exception safety.
Implementing op+= using op+ will necessarily call op=
in its implementation, providing a good single place for
exception safe assignment with roll-back capability.
That's not an issue most of the time. Functions like that
are inlined by any decent compiler.

But inlining works in both cases. The op+ needs to
create a temporary object (namely the result) in any
case, but in the case of using op+= the temporary
object has a named storage. If it is possible to use
new object construction with arguments to create
the result of the addition, as in...

inline Complex operator+( const Complex &lhs,const Complex &rhs )
{
return Complex( lhs.Real()+rhs.Real(),lhs.Imag()+rhs.Imag() );
}

.... then you will generally bypass the extra construction
with most compilers because the unnamed return value
optimization has room to kick in, effectively collapsing
the extra construction with the one that it has to do in
any case.

If it can be implemented as a non-member function using
only the public interface of the class itself, it should. There
has been an article by Scott Meyer in CUJ titled "How
non-members improve encapsulation". (I tried to locate a
link, but the CUJ web site seems to be down. I believe
this link will load the article but I could not verify myself:)

http://www.cuj.com/archive/1802/feature.html

Cheers!

- Risto -
 
Z

Zhenyu Xiong

op + using op+= is as efficient as op + from scratch,
but op+= from scatch is more efficient than op+= using op+

look here:
op += from scratch: no temporary object is needed.
inline const Complex & Complex::eek:perator += (const Complex &right)
{
m_dRe += right.real();
m_dIm += right.imag();
return ( *this );
}
op+ using op+=: only one temp obj is needed
inline Complex operator + (const Complex & left, const Complex &right)
{
Complex temp(left)
return temp += right;
}

op + from scratch: one temp obj is needed
inline Complex operator + (const Complex & left, const Complex &right)
{
return Complex(left.real()+right.real(), left.imag()+right.imag());
}

op+= using op+: at least one temp obj is needed.// operaotr+ needs


op+= can also be a non-member function, but I just think it's ugly.
if a function modifies the object, I prefer to make it a member function.
 
R

Risto Lankinen

Hi!

Zhenyu Xiong said:
op + using op+= is as efficient as op + from scratch,
but op+= from scatch is more efficient than op+= using op+

This is seemingly true, but comes with a catch. Read on...
op+ using op+=: only one temp obj is needed
inline Complex operator + (const Complex & left, const Complex &right)
{
Complex temp(left)
return temp += right;
}


In this case, the algorithm instantiates a named temporary
object. The compiler will be able to use the named return
value optimization *only* if it can prove that the omission
of the constructor and destructor calls for that object do
not cause an observable difference in behaviour. It will be
able to do this only (*) if copy constructor and destructor
are both either defined inline or not declared at all (in which
case default versions will be synthesized by the compiler).
Even then, the defined inline ctor/dtor must not call any
non-inline methods, and the synthesized ctor/dtor will
impose this very same requirement to all of the the class
member variables recursively.

If all of that - and more (#) - is true, then there will only
be one instantiation of the object, namely that to construct
the result.

(*) Footnote: Strictly speaking, for many compilers the
ctor/dtor don't need to be inline as long as they reside
in the same compilation unit. All other caveats still apply,
though.

(#) Footnote: It is of course still possible that even if the
ctor/dtor are inline and call only inline methods, they do
some other things that prevent them from being optimized
away, such as manipulate some reference counter which
is declared as volatile.
op + from scratch: one temp obj is needed
inline Complex operator + (const Complex & left, const Complex &right)
{
return Complex(left.real()+right.real(), left.imag()+right.imag());
}

In this case the algorithm instantiates an unnamed object.
The compiler will be able to use the unnamed return
value optimization, and only one constructor call will be
performed to construct the result, period.

Cheers!

- Risto -
 
R

Rolf Magnus

Risto said:
Hi!



This is seemingly true, but comes with a catch. Read on...



In this case, the algorithm instantiates a named temporary
object. The compiler will be able to use the named return
value optimization *only* if it can prove that the omission
of the constructor and destructor calls for that object do
not cause an observable difference in behaviour. It will be
able to do this only (*) if copy constructor and destructor
are both either defined inline or not declared at all (in which
case default versions will be synthesized by the compiler).
Even then, the defined inline ctor/dtor must not call any
non-inline methods, and the synthesized ctor/dtor will
impose this very same requirement to all of the the class
member variables recursively.

If all of that - and more (#) - is true, then there will only
be one instantiation of the object, namely that to construct
the result.

So would that be better than:

inline Complex operator + (const Complex & left, const Complex
&right)
{
return Complex(left) += right;
}

? Now the returned object is a nameless temporary.
 
R

Risto Lankinen

So would that be better than:

inline Complex operator + (const Complex & left, const Complex
&right)
{
return Complex(left) += right;
}

? Now the returned object is a nameless temporary.

Excellent and very interesting point! I don't know the
answer off-hand, but I found a pair of documents in the
web that might:

The same question asked in Boost mailing list archive:
http://lists.boost.org/MailArchives/boost/msg31235.php

The first follow-up to that question:
http://lists.boost.org/MailArchives/boost/msg31239.php

I haven't checked this myself with any compiler, but the
articles mentioned above hint that your trick may not be
enough to enable the unnamed return value optimization.

Cheers!

- Risto -
 
R

Rob Williscroft

Risto Lankinen wrote in
Hi!



This is seemingly true, but comes with a catch. Read on...



In this case, the algorithm instantiates a named temporary
object. The compiler will be able to use the named return
value optimization *only* if it can prove that the omission
of the constructor and destructor calls for that object do
not cause an observable difference in behaviour.

How so, I was under the impression that (N)RVO was permission
to ignore the posibility of side effects in the copy-ctor and
dtor.

If it isn't I can't think why it would need mentoning in the
standard as *all* it would be is an optimization caried out
under the as-if rule.

It will be
able to do this only (*) if copy constructor and destructor
are both either defined inline or not declared at all (in which
case default versions will be synthesized by the compiler).
Even then, the defined inline ctor/dtor must not call any
non-inline methods, and the synthesized ctor/dtor will
impose this very same requirement to all of the the class
member variables recursively.

[snip]

Are you sure you aren't talking about cases where (N)RVO appears
to occur even though the compiler has no specific support for
(N)RVO, i.e. it has a good optimiser.

Note that good optimisers have been around alot longer than
(N)RVO supporting compilers.

[snip]

Rob.
 

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
474,145
Messages
2,570,824
Members
47,370
Latest member
desertedtyro29

Latest Threads

Top