473,320 Members | 1,950 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,320 software developers and data experts.

grr... this old nut

I have done this before but it keeps eluding me when I revisit it...

I have a class employee defined with;

friend employee operator+(const employee& e1, const employee& e2) ;
Now I know I can invoke that version of the operator by using
something like;
employee e1, e2;

employee e3 = operator+(e1,e2);
however I know there are other ways to have it invoked...thereby
illustrating its use. What other ways are there? I thought
employee e4 = e1+e2+e3;

would do the trick but that doesn't invoke it (using latest G++
compiler).
any help much appreciated.
cheers

GrahamO
Jul 22 '05 #1
37 1442

"grahamo" <gr************@hotmail.com> wrote in message
news:79**************************@posting.google.c om...
I have done this before but it keeps eluding me when I revisit it...

I have a class employee defined with;

friend employee operator+(const employee& e1, const employee& e2) ;
Now I know I can invoke that version of the operator by using
something like;
employee e1, e2;

employee e3 = operator+(e1,e2);
however I know there are other ways to have it invoked...thereby
illustrating its use. What other ways are there? I thought
employee e4 = e1+e2+e3;

would do the trick but that doesn't invoke it (using latest G++
compiler).
any help much appreciated.
cheers

GrahamO


It should work like that. Can you supply a complete program and explain what
happens instead.

john
Jul 22 '05 #2

"John Harrison" <jo*************@hotmail.com> wrote in message
news:2l************@uni-berlin.de...

"grahamo" <gr************@hotmail.com> wrote in message
news:79**************************@posting.google.c om...
I have done this before but it keeps eluding me when I revisit it...

I have a class employee defined with;

friend employee operator+(const employee& e1, const employee& e2) ;
Now I know I can invoke that version of the operator by using
something like;
employee e1, e2;

employee e3 = operator+(e1,e2);
however I know there are other ways to have it invoked...thereby
illustrating its use. What other ways are there? I thought
employee e4 = e1+e2+e3;

would do the trick but that doesn't invoke it (using latest G++
compiler).
any help much appreciated.
cheers

GrahamO
It should work like that. Can you supply a complete program and explain

what happens instead.

john
Doesn't the function have to be const in order to chain it like that, since
e1+e2+e3 creates a temporary (or two)?

-Howard


Jul 22 '05 #3
grahamo wrote:
I have done this before but it keeps eluding me when I revisit it...

I have a class employee defined with;

friend employee operator+(const employee& e1, const employee& e2) ;


It would help if you post minimal, yet compilable code that demonstrates
the problem you are having. Do you mean that operator+() is a member
function of the employee class?
In that case it should only have one employee argument:

class employee
{
public:
employee operator+(const employee& e2)
{
// Return the sum of *this and e2...
}
};

You could also declare the operator+() function outside the scope of the
employee class. In that case you do need two employee arguments. Since
only friends can touch your employee's private parts, you may have to
make operator+(const employee& e1, const employee& e2) a friend of employee:

class employee
{
// Only needed if operator+() needs to have access to employees
// privates.
friend employee operator+(const employee& e1, const employee& e2);

// ...other stuff...

};

employee operator+(const employee& e1, const employee& e2)
{
// Return the sum of e1 and e2...
}

Anyway, defining an operator+() for employees seems to be an excellent
example of inappropriate use of operator overloading. To me it is not
obvious what happens if you add two employees. Does it mean that e1 and
e2 have intercourse and produce another employee... in that case the
multiplication operator would be more appropriate ;-)

--
Peter van Merkerk
peter.van.merkerk(at)dse.nl
Jul 22 '05 #4
"Howard" <al*****@hotmail.com> wrote in
news:NG*******************@bgtnsc05-news.ops.worldnet.att.net:

"John Harrison" <jo*************@hotmail.com> wrote in message
news:2l************@uni-berlin.de...

"grahamo" <gr************@hotmail.com> wrote in message
news:79**************************@posting.google.c om...
> I have done this before but it keeps eluding me when I revisit
> it...
>
> I have a class employee defined with;
>
> friend employee operator+(const employee& e1, const employee& e2)
> ;
>
>
> Now I know I can invoke that version of the operator by using
> something like;
>
>
> employee e1, e2;
>
> employee e3 = operator+(e1,e2);
>
>
> however I know there are other ways to have it invoked...thereby
> illustrating its use. What other ways are there? I thought
>
>
> employee e4 = e1+e2+e3;
>
> would do the trick but that doesn't invoke it (using latest G++
> compiler).
>
>
> any help much appreciated.
>
>
> cheers
>
> GrahamO


It should work like that. Can you supply a complete program and
explain

what
happens instead.

john


Doesn't the function have to be const in order to chain it like that,
since e1+e2+e3 creates a temporary (or two)?


It's a freestanding function (it's not a member function, only a friend),
it can't be const.
Jul 22 '05 #5

"Andre Kostur" <nn******@kostur.net> wrote in message
news:Xn*******************************@207.35.177. 135...
"Howard" <al*****@hotmail.com> wrote in
news:NG*******************@bgtnsc05-news.ops.worldnet.att.net:

"John Harrison" <jo*************@hotmail.com> wrote in message
news:2l************@uni-berlin.de...

"grahamo" <gr************@hotmail.com> wrote in message
news:79**************************@posting.google.c om...
> I have done this before but it keeps eluding me when I revisit
> it...
>
> I have a class employee defined with;
>
> friend employee operator+(const employee& e1, const employee& e2)
> ;
>
>
> Now I know I can invoke that version of the operator by using
> something like;
>
>
> employee e1, e2;
>
> employee e3 = operator+(e1,e2);
>
>
> however I know there are other ways to have it invoked...thereby
> illustrating its use. What other ways are there? I thought
>
>
> employee e4 = e1+e2+e3;
>
> would do the trick but that doesn't invoke it (using latest G++
> compiler).
>
>
> any help much appreciated.
>
>
> cheers
>
> GrahamO

It should work like that. Can you supply a complete program and
explain

what
happens instead.

john


Doesn't the function have to be const in order to chain it like that,
since e1+e2+e3 creates a temporary (or two)?


It's a freestanding function (it's not a member function, only a friend),
it can't be const.


Oops! :-) I was thinking of a member function returning a reference. I
realized my mistake immediately, and cancelled my post seconds after sending
it, but I guess it still shows up for some people. Sorry.

-Howard

Jul 22 '05 #6
On Tue, 13 Jul 2004 05:40:58 -0700, grahamo wrote:
I have done this before but it keeps eluding me when I revisit it...

I have a class employee defined with;

friend employee operator+(const employee& e1, const employee& e2) ;
It is better to implement the free operator+ in terms of the member
operator+=, which makes the friendship unnecessary.

[...]
employee e4 = e1+e2+e3;

would do the trick but that doesn't invoke it (using latest G++
compiler).


Here is an example:

class C
{
int i_;

public:

explicit C(int i)
:
i_(i)
{}

C & operator+= (C const & other)
{
i_ += other.i_;
return *this;
}

int value() const
{
return i_;
}
};

C operator+ (C const & lhs, C const & rhs)
{
C result(lhs);
return result += rhs;
}

#include <iostream>

int main()
{
C const one(1);
C const two(2);
C const three(3);
C const result = one + two + three;

std::cout << result.value() << '\n';
}

Ali
Jul 22 '05 #7

"Ali Cehreli" <ac******@yahoo.com> wrote in message
news:pa*********************************@yahoo.com ...
C operator+ (C const & lhs, C const & rhs)
{
C result(lhs);
return result += rhs;
}


Is that legal? I'd think that it might invoke undefined behavior (but I'm
probably wrong. :-)) Even if it works, though, I'd prefer to break it into
two lines:

C operator+ (C const & lhs, C const & rhs)
{
C result(lhs);
result += rhs;
return result;
}

Operator += returns a reference to result, which is then returned as n
object (not a reference), so I guess a copy must be made there (skipping
over possible optimizations, of course). So I guess it's ok, but it just
looks ugly to me, and performs multiple actions on one line (calling the
operator and then returning a copy of that result), something I'm loathe to
do.

-Howard
Jul 22 '05 #8
On Tue, 13 Jul 2004 12:43:48 -0700, Howard wrote:

"Ali Cehreli" <ac******@yahoo.com> wrote in message
news:pa*********************************@yahoo.com ...
C operator+ (C const & lhs, C const & rhs) {
C result(lhs);
return result += rhs;
}

Is that legal? I'd think that it might invoke undefined behavior (but
I'm probably wrong. :-)) Even if it works, though, I'd prefer to break
it into two lines:

C operator+ (C const & lhs, C const & rhs) {
C result(lhs);
result += rhs;
return result;
}

Operator += returns a reference to result, which is then returned as n
object (not a reference), so I guess a copy must be made there (skipping
over possible optimizations, of course). So I guess it's ok, but it
just looks ugly to me, and performs multiple actions on one line
(calling the operator and then returning a copy of that result),
something I'm loathe to do.

-Howard


It is all legal as you described. Actually I thought at least three times
before posting that code. I would have written what you suggested if I
thought just one more time :)

Ali
Jul 22 '05 #9
Peter van Merkerk <me*****@deadspam.com> wrote in message news:<2l************@uni-berlin.de>...
grahamo wrote:

<snip>

class employee
{
public:
employee operator+(const employee& e2)
{
// Return the sum of *this and e2...
}
};

You could also declare the operator+() function outside the scope of the
employee class. In that case you do need two employee arguments. Since
only friends can touch your employee's private parts, you may have to
make operator+(const employee& e1, const employee& e2) a friend of employee:

class employee
{
// Only needed if operator+() needs to have access to employees
// privates.
friend employee operator+(const employee& e1, const employee& e2);

// ...other stuff...

};

employee operator+(const employee& e1, const employee& e2)
{
// Return the sum of e1 and e2...
}

Anyway, defining an operator+() for employees seems to be an excellent
example of inappropriate use of operator overloading. To me it is not
obvious what happens if you add two employees. Does it mean that e1 and
e2 have intercourse and produce another employee... in that case the
multiplication operator would be more appropriate ;-)

Shouldn't operator+ return a const object ? I mean

const employee operator+(const employee& e1, const employee& e2)
{
......
}

Otherwise you can write

employee e1,e2,e3;
(e1+e2) = e3;

-Arijit
Jul 22 '05 #10
Arijit wrote:
Shouldn't operator+ return a const object ? I mean

const employee operator+(const employee& e1, const employee& e2)
{
.....
}

Otherwise you can write

employee e1,e2,e3;
(e1+e2) = e3;


I see your point. But even the standard library (e.g. std::string)
doesn't do this, so I guess I'm in good company ;-)

Could someone explain why the standard library does not return const
objects with operator+()?

--
Peter van Merkerk
peter.van.merkerk(at)dse.nl
Jul 22 '05 #11
Could someone explain why the standard library does not return const objects with operator+()?


It's redundant.
Take the following:

int GetNumber();

int main()
{
const int& p = GetNumber();
}

int GetNumber()
{
int k = 42;

--k;

k /= 2;

k = 6 / k;

return k;
}
See how I bound the return value to a const reference, I
had no choice in the matter. What's returned from that
function, and from your operator+, is a "temporary".

What's a temporary? It's a const object that goes out of
scope at the next semicolon. So take the following:

void Blah(const int&);

int main()
{
int p = 42;

Blah(p + 7);
}
What gets passed to Blah? A temporary, it only exists for
as long as it has to, and it can't be edited, it's const.
This particular temporary is destroyed immediately at the
next semicolon, ASAP.
So... return values. They come in two forms:

Type A)

int Blah();
int* Glah();

Here, what's being returned is just a temporary. A
temporary is const, so sticking const in there would be
like calling out "Forename Surname" to your own sister, ie.
it's redundant.
Type B)

int& Blah();

Here, what's being returned is an actual reference to an
object. Here, specifying const will actually make a
difference:

int& AA();
const int& BB();

int main()
{
AA() = 5;

BB() = 6; //Compile ERROR
}
Anyway, without ranting-on too much, all that's being
returned form your Type A functions is a simple temporary,
they're automatically const, so you don't have to specify
it, you don't have a choice either way.

And remember, it's just a temporary!

-JKop
Jul 22 '05 #12
On Wed, 14 Jul 2004 22:22:29 GMT, JKop <NU**@NULL.NULL> wrote:
Here, what's being returned is just a temporary. A
temporary is const, so sticking const in there would be
like calling out "Forename Surname" to your own sister, ie.
it's redundant.


Not that myth again. A temporary is not const, here is the proof

class X
{
public:
void a_non_const_method()
{
x = 1;
}
private:
int x;
};

X func()
{
X
return x;
}

int main()
{
func().a_non_const_method();
}

The correct rule is that a temporary may not be bound to a noo-const
reference, which isn't the same thing at all.

john
Jul 22 '05 #13
>Shouldn't operator+ return a const object ? I mean

const employee operator+(const employee& e1, const employee& e2)
{
.....
}

Otherwise you can write

employee e1,e2,e3;
(e1+e2) = e3;


I have never understood why a return value that is of class type is modifiable
when a return value that is of primitive type is not modifiable.

<CODE>

#include <string>
using std::string;

string ReturnClassType()
{
return "";
}

int ReturnPrimitiveType()
{
return 0;
}

int main()
{
//This is okay!
ReturnClassType() = "";

//This is not okay!
ReturnPrimitiveType() = 0;

return 0;
}

</CODE>

This seems like an inconsistency to me. Both functions return temporary
objects yet one temporary is modifiable and the other temporary is not.

It seems as though one is an l-value and the other is not.

Can anyone help me to understand this?

This was actually discussed months ago and I did not grok the replies I
received. I will look at them again. Until then if anyone can steer me in the
right direction I would appreciate it.


Jul 22 '05 #14
Can anyone help me to understand this?

Sure I can, you ain't got a C++ compiler there.

Get yourself a "C++ compiler" and compile it (or attempt to
do so), and then all will become clear.
-JKop
Jul 22 '05 #15
JKop posted:
Can anyone help me to understand this?

Sure I can, you ain't got a C++ compiler there.

Get yourself a "C++ compiler" and compile it (or attempt to
do so), and then all will become clear.
-JKop

Sorry!

I let my arrogance get ahead of me there.

After having posted that, I realized that it was very likely that you had
tested your code and so I tried to compile it myself, and to my disgust, it
compiled.

Since when can a temporary be an l-value?
-JKop
Jul 22 '05 #16
On Tue, 13 Jul 2004 19:43:48 GMT, "Howard" <al*****@hotmail.com>
wrote:

"Ali Cehreli" <ac******@yahoo.com> wrote in message
news:pa*********************************@yahoo.co m...
C operator+ (C const & lhs, C const & rhs)
{
C result(lhs);
return result += rhs;
}


Is that legal? I'd think that it might invoke undefined behavior (but I'm
probably wrong. :-)) Even if it works, though, I'd prefer to break it into
two lines:

C operator+ (C const & lhs, C const & rhs)
{
C result(lhs);
result += rhs;
return result;
}

Operator += returns a reference to result, which is then returned as n
object (not a reference), so I guess a copy must be made there (skipping
over possible optimizations, of course). So I guess it's ok, but it just
looks ugly to me, and performs multiple actions on one line (calling the
operator and then returning a copy of that result), something I'm loathe to
do.


The most efficient implementation is actually a bit weird:

C operator+ (C lhs, C const & rhs)
{
lhs += rhs;
return lhs;
}

That is potentially more efficient when a temporary is passed as the
first parameter. e.g.
C() + C();

Tom
Jul 22 '05 #17
The most efficient implementation is actually a bit weird:
C operator+ (C lhs, C const & rhs)
{
lhs += rhs;
return lhs;
}

That is potentially more efficient when a temporary is passed as the first parameter. e.g.
C() + C();

Or maybe even:

C operator+(const C& lhs, const C& rhs)
{
C temp = lhs;

return temp += rhs;
}
-JKop
Jul 22 '05 #18
On Thu, 15 Jul 2004 17:09:16 GMT, JKop <NU**@NULL.NULL> wrote:
The most efficient implementation is actually a bit

weird:

C operator+ (C lhs, C const & rhs)
{
lhs += rhs;
return lhs;
}

That is potentially more efficient when a temporary is

passed as the
first parameter. e.g.
C() + C();

Or maybe even:

C operator+(const C& lhs, const C& rhs)
{
C temp = lhs;

return temp += rhs;
}


Nope, that gets rid of the efficiency gain from passing lhs by value.
Consider:

C aC(C() + c); //c is some value of type c

Your version has (assuming NRVO)
1 default constructor call
1 copy constructor call

My version has (same assumption)
1 default constructor call

IOW, the parameter ends up being constructed right inside the return
value!

Tom
Jul 22 '05 #19
tom_usenet posted:
Nope, that gets rid of the efficiency gain from passing lhs by value. Consider:

C aC(C() + c); //c is some value of type c

Your version has (assuming NRVO)
1 default constructor call
1 copy constructor call

My version has (same assumption)
1 default constructor call

IOW, the parameter ends up being constructed right inside the return value!

Tom

Okay, I'll get rid of that extra constructor (which
would'be been optimized away in anyway!) with:

C operator+(const C& lhs, const C& rhs)
{
C temp(lhs);

return temp += rhs;
}
Check.
-JKop
Jul 22 '05 #20
JKop <NU**@NULL.NULL> wrote in message news:<z%*****************@news.indigo.ie>...
Can anyone help me to understand this?

Sure I can, you ain't got a C++ compiler there.

Get yourself a "C++ compiler" and compile it (or attempt to
do so), and then all will become clear.
-JKop


The compiler is perfectly alright. Temporaries are not
constant. Rather, they are rvalues.

-Arijit
Jul 22 '05 #21
da*********@aol.com (DaKoadMunky) wrote in message news:<20***************************@mb-m04.aol.com>...
I have never understood why a return value that is of class type is modifiable
when a return value that is of primitive type is not modifiable.

<CODE>

#include <string>
using std::string;

string ReturnClassType()
{
return "";
}

int ReturnPrimitiveType()
{
return 0;
}

int main()
{
//This is okay!
ReturnClassType() = "";

//This is not okay!
ReturnPrimitiveType() = 0;

return 0;
}

</CODE>

This seems like an inconsistency to me. Both functions return temporary
objects yet one temporary is modifiable and the other temporary is not.

It seems as though one is an l-value and the other is not.

Can anyone help me to understand this?


No, both are rvalues. Built in assignment operator expects its left
hand operand to be lvalue. So compiler gives an error. But for string,
the actual call is

ReturnClassType().operator=( string("") );

Since temporaries are not const, you can invoke operator= on it.
So the code compiles.
The only way to stop it is to return const from functions.

-Arijit
Jul 22 '05 #22
Arijit wrote:
da*********@aol.com (DaKoadMunky) wrote in message news:<20***************************@mb-m04.aol.com>...

I have never understood why a return value that is of class type is modifiable
when a return value that is of primitive type is not modifiable.

<CODE>

#include <string>
using std::string;

string ReturnClassType()
{
return "";
}

int ReturnPrimitiveType()
{
return 0;
}

int main()
{
//This is okay!
ReturnClassType() = "";

//This is not okay!
ReturnPrimitiveType() = 0;

return 0;
}

</CODE>

This seems like an inconsistency to me. Both functions return temporary
objects yet one temporary is modifiable and the other temporary is not.

It seems as though one is an l-value and the other is not.

Can anyone help me to understand this?

No, both are rvalues. Built in assignment operator expects its left
hand operand to be lvalue. So compiler gives an error. But for string,
the actual call is

ReturnClassType().operator=( string("") );

Since temporaries are not const, you can invoke operator= on it.
So the code compiles.
The only way to stop it is to return const from functions.


The question remains why doesn't the standard library return const objects?

--
Peter van Merkerk
peter.van.merkerk(at)dse.nl
Jul 22 '05 #23
Arijit posted:

No, both are rvalues. Built in assignment operator expects its left hand operand to be lvalue. So compiler gives an error. But for string, the actual call is

ReturnClassType().operator=( string("") );

Since temporaries are not const, you can invoke operator= on it. So the code compiles.
The only way to stop it is to return const from functions.
-Arijit

Very interesting.
-JKop
Jul 22 '05 #24
On Thu, 15 Jul 2004 18:19:37 GMT, JKop <NU**@NULL.NULL> wrote:
tom_usenet posted:
Nope, that gets rid of the efficiency gain from passing

lhs by value.
Consider:

C aC(C() + c); //c is some value of type c

Your version has (assuming NRVO)
1 default constructor call
1 copy constructor call

My version has (same assumption)
1 default constructor call

IOW, the parameter ends up being constructed right inside

the return
value!

Tom

Okay, I'll get rid of that extra constructor (which
would'be been optimized away in anyway!) with:

C operator+(const C& lhs, const C& rhs)
{
C temp(lhs);

return temp += rhs;
}
Check.


For

C v(C() + c);

On both GCC and VC 7.1 your version does:

Default
Copy
Operator+=
Copy
Destroy
Destroy

Mine does:

Default
Operator+=
Copy
Destroy

If you pass the first parameter by reference it will always be copied
in your "C temp(lhs)" line. If you pass it by value the copy will
sometimes be optimized out (specifically when a temporary is passed).

Tom
Jul 22 '05 #25
tom_usenet posted:

If you pass the first parameter by reference it will always be copied in your "C temp(lhs)" line. If you pass it by value the copy will sometimes be optimized out (specifically when a temporary is passed).
Tom

But the original object in the calling function would have
to be copied before the function is called - it can't just
simply use the one from the calling function, unless
ofcourse its inline, but otherwise, you'd need a reference
to the object in the calling function.

Your code does "show" a copy constructor because the object
is copied even before the function starts.
-JKop

Jul 22 '05 #26
Peter van Merkerk <me*****@deadspam.com> wrote in message news:<2l************@uni-berlin.de>...

<snip>
The question remains why doesn't the standard library return const objects?


Not a clue.

-Arijit
Jul 22 '05 #27
On Thu, 15 Jul 2004 22:12:16 +0200, Peter van Merkerk
<me*****@deadspam.com> wrote:
Can anyone help me to understand this?

No, both are rvalues. Built in assignment operator expects its left
hand operand to be lvalue. So compiler gives an error. But for string,
the actual call is

ReturnClassType().operator=( string("") );

Since temporaries are not const, you can invoke operator= on it.
So the code compiles.
The only way to stop it is to return const from functions.


The question remains why doesn't the standard library return const objects?


You gain no useful safety, and you lose optimization possibilities. If
you do:

C c(ReturnClassType());

If ReturnClassType returns a const object, that has to be copied into
c. If it returns a non-const object, RVO can apply and the return
value can be directly constructed inside c.

Also, there are legitimate reasons to want to call non-const functions
on return values, particularly when the non-const function returns the
original object. e.g. something like

f(get_some_string().insert(0, " extra bit"));

Obviously, you could split it into more lines, but then, if the
get_some_string() method returns a const string, an extra copy will
have to be made.

Basically, I see no point in defending yourself against errors that
you've never made!

Tom
Jul 22 '05 #28
On Fri, 16 Jul 2004 08:53:15 GMT, JKop <NU**@NULL.NULL> wrote:
tom_usenet posted:

If you pass the first parameter by reference it willalways be copied
in your "C temp(lhs)" line. If you pass it by value the

copy will
sometimes be optimized out (specifically when a temporary

is passed).

Tom

But the original object in the calling function would have
to be copied before the function is called - it can't just
simply use the one from the calling function, unless
ofcourse its inline, but otherwise, you'd need a reference
to the object in the calling function.


No, it *can* just use the one from the calling function - that's the
whole point of passing it by value. See 12.8/15 of the standard.
Your code does "show" a copy constructor because the object
is copied even before the function starts.


Nope, try it for yourself:

#include <iostream>

class C
{
public:
C()
{
std::cout << "Default\n";
}
C(C const&)
{
std::cout << "Copy\n";
}
~C()
{
std::cout << "Destroy\n";
}

C& operator=(C const&)
{
std::cout << "Assign\n";
}

C& operator+=(C const&)
{
std::cout << "+=\n";
return *this;
}
};

#ifdef TOM
C operator+(C lhs, const C& rhs)
{
return lhs += rhs;
}
#else
C operator+(C const& lhs, const C& rhs)
{
C temp(lhs);
return temp += rhs;
}
#endif

int main()
{
C c;
std::cout << "Test:\n";
C v(C() + c);
std::cout << "Test end\n";
}
Tom
Jul 22 '05 #29
tom_usenet posted:
No, it *can* just use the one from the calling function - that's the
whole point of passing it by value. See 12.8/15 of the standard.
If that's true, then in the *your* code, you're changing the original.

We haven't got an operator+= here, we've got an operator+.

But alas, the original remains unchanged. Why? because "lhs" is *NOT* the
original object from the calling function, it's a local non-const object
which has been copy-constructed from the supplied object in main, and as
such, you can do whatever you like with it, including an operator+=!

C operator+(C lhs, const C& rhs)
{
return lhs += rhs;
}

"lhs", before any of the body of code is executed, is copy contructed from
the object supplied in the calling function.
Let's examine the two samples. If you don't mind, I'm going to change the
name of the class, it's distracting me. *Your* sample:

Monkey operator+(Monkey lhs, const Monkey& rhs)
{
return lhs += rhs;
}
And *my* sample:

Monkey operator+(const Monkey& lhs, const Monkey& rhs)
{
Monkey temp_monkey(lhs);

return temp_monkey += rhs;
}
Before going further, my argument is *NOT* that either sample is superior,
but that *neither* is superior.

Here's some code that'll work with objects of our class:

int main()
{
Monkey pet_monkey(5); //Let's pretend it has such a constructor

Monkey wild_monkey(18);

Monkey domesticated_monkey(pet_monkey + wild_monkey);
}
When *your* code is called, a Monkey object is copy-constructed from
"pet_monkey" before the body of the "operator+" function is executed. So now
you can do whatever you want with this "copy", and evidently you *are*,
you're changind it, you're performing a += on it. You argue that you're
working with the original object from the calling function; if this is so,
then the original object would be changed by the +=.
Answer: The original object isn't changed because you're not *working* with
the original object, you're working with a non-const local object in the
operator+ function.... which has been copy-constructed from the pet_monkey
object in main(). When the operator+ fuction comes to the end of its
execution, the local "copy" is destroyed.

When *my* code is called, (assuming a stack and register system), my
operator+ function will be supplied with two "hidden pointer"s. Then, I
define a local non-const object, which I copy-construct from pet_monkey.
Then I do a += on this "copy". My "copy" is destroyed when the operator+
function reaches the end of its execution.

So, with *your* code:

Copy-constructed object
operator+=
Destruction of copy-constructed object
with *my* code:

Copy-constructed object
operator+=
Destruction of copy-constructed object

-JKop
Jul 22 '05 #30
tom_usenet wrote:
On Thu, 15 Jul 2004 22:12:16 +0200, Peter van Merkerk
<me*****@deadspam.com> wrote:
The question remains why doesn't the standard library return const objects?


You gain no useful safety, and you lose optimization possibilities. If
you do:

C c(ReturnClassType());

If ReturnClassType returns a const object, that has to be copied into
c. If it returns a non-const object, RVO can apply and the return
value can be directly constructed inside c.

Also, there are legitimate reasons to want to call non-const functions
on return values, particularly when the non-const function returns the
original object. e.g. something like

f(get_some_string().insert(0, " extra bit"));

Obviously, you could split it into more lines, but then, if the
get_some_string() method returns a const string, an extra copy will
have to be made.

Basically, I see no point in defending yourself against errors that
you've never made!


Thanks Tom, that was the kind of answer I was looking for.

--
Peter van Merkerk
peter.van.merkerk(at)dse.nl
Jul 22 '05 #31
On Fri, 16 Jul 2004 14:37:44 +0200, Peter van Merkerk
<me*****@deadspam.com> wrote:
Thanks Tom, that was the kind of answer I was looking for.


Whoops, this bit was a lie actually:
You gain no useful safety, and you lose optimization possibilities. If
you do:

C c(ReturnClassType());

If ReturnClassType returns a const object, that has to be copied into
c. If it returns a non-const object, RVO can apply and the return
value can be directly constructed inside c.


The optimization is still allowed if ReturnClassType returns a const
C. What I actually meant to say was something about move constructors.
See here:
http://www.open-std.org/jtc1/sc22/wg...004/n1610.html
Basically, a const rvalue can't be moved, whilst a non-const one can.
Making rvalues const unnecessarily just removes optimization
possibilities.

Tom
Jul 22 '05 #32
On Fri, 16 Jul 2004 11:25:35 GMT, JKop <NU**@NULL.NULL> wrote:
tom_usenet posted:
No, it *can* just use the one from the calling function - that's the
whole point of passing it by value. See 12.8/15 of the standard.
If that's true, then in the *your* code, you're changing the original.


Yes, and since it's a temporary, that's fine.
We haven't got an operator+= here, we've got an operator+.
Indeed.
But alas, the original remains unchanged. Why? because "lhs" is *NOT* the
original object from the calling function, it's a local non-const object
which has been copy-constructed from the supplied object in main, and as
such, you can do whatever you like with it, including an operator+=!
However, if you pass a temporary, it *is* the orginal object from the
calling function.
C operator+(C lhs, const C& rhs)
{
return lhs += rhs;
}

"lhs", before any of the body of code is executed, is copy contructed from
the object supplied in the calling function.


What I'm getting very tired of telling you is that this isn't always
the case. It *isn't* copy constructed when a temporary is passed.
Let's examine the two samples. If you don't mind, I'm going to change the
name of the class, it's distracting me. *Your* sample:

Monkey operator+(Monkey lhs, const Monkey& rhs)
{
return lhs += rhs;
}
And *my* sample:

Monkey operator+(const Monkey& lhs, const Monkey& rhs)
{
Monkey temp_monkey(lhs);

return temp_monkey += rhs;
}
Before going further, my argument is *NOT* that either sample is superior,
but that *neither* is superior.
The former is superior when a temporary is passed as the first
parameter.

Here's some code that'll work with objects of our class:

int main()
{
Monkey pet_monkey(5); //Let's pretend it has such a constructor

Monkey wild_monkey(18);

Monkey domesticated_monkey(pet_monkey + wild_monkey);
That isn't my example. My example was:

Monkey domesticated_monkey(Monkey(5) + wild_monkey);

i.e. passing a temporary as the first object.
}
When *your* code is called, a Monkey object is copy-constructed from
"pet_monkey" before the body of the "operator+" function is executed.


Nope, the copy construction doesn't happen for a temporary - the
temporary is "elided".

If you don't get it by now, you never will. Did you even run my
example code?

Tom
Jul 22 '05 #33
tom_usenet posted:
Monkey domesticated_monkey(Monkey(5) + wild_monkey);

Then you're right.
What's the name of that optimization?
-JKop
Jul 22 '05 #34
On Fri, 16 Jul 2004 16:02:03 GMT, JKop <NU**@NULL.NULL> wrote:
tom_usenet posted:
Monkey domesticated_monkey(Monkey(5) + wild_monkey);

Then you're right.
What's the name of that optimization?


I'm not sure it has an official name, but "temporary elision" seems to
fit in with the wording in the standard, or you could call it "copy
elision" or "copy constructor elision".

Tom
Jul 22 '05 #35
>No, both are rvalues.

I know the writings of bs should not be substituted for the standard, but his
glossary at http://www.research.att.com/~bs/glossary.html indicates that an
rvalue is...

"an expression that may appear on the right-hand side of an assignment, but not
of the left-hand side."

I understand that...

ReturnClassType() = ""; //1

is really just...

ReturnClassType().operator=( string("") ); //2

But 1 has to be translated to 2 at compile time. At compile time 1 has a
supposed rvalue on the left hand side of an assignment statement yet this is
not considered an error.

Is the bs definition of rvalue a little bit off with respect to the standard?

Am I making a mistake equating constancy with rvalues?


Jul 22 '05 #36
When we say that r-values are const, that temporaries are
const, we mean the following:

int Cow()
{
int monkey = 876;

return monkey;
}
int main()
{
Cow() = 46; //ERROR
}
But, if we turn that into a class:

class Blah{ };

Blah Cow()
{
Blah monkey;

return monkey;
}

int main()
{
Cow() = Blah();
}
The only explanation that can explain how an r-value is on
the left hand side of an assignment operator is as
follows... It isn't! We just have to accept that according
to the Standard, there's no assignment operator there, it's
really:

Blah::operator=(const Blah&);

A plain old run-of-the-mill function - a plain old run-of-
the-mill *non-const* function, I might add.
-JKop
Jul 22 '05 #37
On Thu, 15 Jul 2004 17:54:03 +0100, tom_usenet
<to********@hotmail.com> wrote:

[snip]
The most efficient implementation is actually a bit weird:

C operator+ (C lhs, C const & rhs)
{
lhs += rhs;
return lhs;
}

That is potentially more efficient when a temporary is passed as the
first parameter. e.g.
C() + C();

Tom


Perhaps I'm just allergic to passing class types by value...but
doesn't it depend on what operator+= actually does?

IMHO a better design would be to factor out work done by operator+=
and operator+ into a private helper function which can be called by
both (in which case operator+ needs to be a friend). Then one could
pass the arguments by const & as is usually done.
--
Bob Hairgrove
No**********@Home.com
Jul 22 '05 #38

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

3
by: William C. White | last post by:
Does anyone know of a way to use PHP /w Authorize.net AIM without using cURL? Our website is hosted on a shared drive and the webhost company doesn't installed additional software (such as cURL)...
2
by: Albert Ahtenberg | last post by:
Hello, I don't know if it is only me but I was sure that header("Location:url") redirects the browser instantly to URL, or at least stops the execution of the code. But appearantely it continues...
3
by: James | last post by:
Hi, I have a form with 2 fields. 'A' 'B' The user completes one of the fields and the form is submitted. On the results page I want to run a query, but this will change subject to which...
0
by: Ollivier Robert | last post by:
Hello, I'm trying to link PHP with Oracle 9.2.0/OCI8 with gcc 3.2.3 on a Solaris9 system. The link succeeds but everytime I try to run php, I get a SEGV from inside the libcnltsh.so library. ...
1
by: Richard Galli | last post by:
I want viewers to compare state laws on a single subject. Imagine a three-column table with a drop-down box on the top. A viewer selects a state from the list, and that state's text fills the...
4
by: Albert Ahtenberg | last post by:
Hello, I have two questions. 1. When the user presses the back button and returns to a form he filled the form is reseted. How do I leave there the values he inserted? 2. When the...
1
by: inderjit S Gabrie | last post by:
Hi all Here is the scenerio ...is it possibly to do this... i am getting valid course dates output on to a web which i have designed ....all is okay so far , look at the following web url ...
2
by: Jack | last post by:
Hi All, What is the PHP equivilent of Oracle bind variables in a SQL statement, e.g. select x from y where z=:parameter Which in asp/jsp would be followed by some statements to bind a value...
3
by: Sandwick | last post by:
I am trying to change the size of a drawing so they are all 3x3. the script below is what i was trying to use to cut it in half ... I get errors. I can display the normal picture but not the...
0
by: ryjfgjl | last post by:
ExcelToDatabase: batch import excel into database automatically...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: Vimpel783 | last post by:
Hello! Guys, I found this code on the Internet, but I need to modify it a little. It works well, the problem is this: Data is sent from only one cell, in this case B5, but it is necessary that data...
0
by: ArrayDB | last post by:
The error message I've encountered is; ERROR:root:Error generating model response: exception: access violation writing 0x0000000000005140, which seems to be indicative of an access violation...
1
by: PapaRatzi | last post by:
Hello, I am teaching myself MS Access forms design and Visual Basic. I've created a table to capture a list of Top 30 singles and forms to capture new entries. The final step is a form (unbound)...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
1
by: Shællîpôpï 09 | last post by:
If u are using a keypad phone, how do u turn on JavaScript, to access features like WhatsApp, Facebook, Instagram....
0
by: af34tf | last post by:
Hi Guys, I have a domain whose name is BytesLimited.com, and I want to sell it. Does anyone know about platforms that allow me to list my domain in auction for free. Thank you
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.