struct/class return by value and assignment

D

Daniel

So why does the following compile? (g++ and comeau)
struct F{
int i;
};
F f() { return F();}
void function() {
f()=F();
}

If I replace F with int (or return a pointer pointer), the compiler
gives the expected message that the return of f() is not an l-value.
But it compiles fine as above (just produces unexpected results). This
came up with a class which has operator[] which returns by value and
allowed c[10]=value; to compile, but have no actual effects. I guess
the right solution is to return a "F const" (in generic code, so it
works with pointers too) or a const &.

Should such compile? And why is a builtin type different from a struct
in this context? Thanks.
--Daniel
 
J

James Kanze

So why does the following compile? (g++ and comeau)
struct F{
int i;};
F f() { return F();}
void function() {
f()=F();
}

The simple, usless answer is: because the standard requires it.
If I replace F with int (or return a pointer pointer), the
compiler gives the expected message that the return of f() is
not an l-value. But it compiles fine as above (just produces
unexpected results). This came up with a class which has
operator[] which returns by value and allowed c[10]=value; to
compile, but have no actual effects. I guess the right
solution is to return a "F const" (in generic code, so it
works with pointers too) or a const &.
Should such compile? And why is a builtin type different from
a struct in this context?

The reason struct is different from other types in this context
is because assignment isn't a built-in operator, but rather an
overloaded operator, and an overloaded operator is a function,
and obeys the rules for functions, and not the rules for the
original operator. Thus, in this case, the rules for the built
in assignment require that the left hand operand be an lvalue,
i.e. not a temporary, but the rules allow you to call a member
function on a temporary. Your line is exactly the same as if
you'd written:
f().operator=(F());

Note that this is true whether or not you explicitly declare an
assignment operator. If you don't declare one, the compiler
declares one for you, but it is still an implicitly declared
function, and *not* the built-in assignment operator.
 
D

Daniel Pitts

Daniel said:
So why does the following compile? (g++ and comeau)
struct F{
int i;
};
F f() { return F();}
void function() {
f()=F();
}

If I replace F with int (or return a pointer pointer), the compiler
gives the expected message that the return of f() is not an l-value.
But it compiles fine as above (just produces unexpected results). This
came up with a class which has operator[] which returns by value and
allowed c[10]=value; to compile, but have no actual effects. I guess
the right solution is to return a "F const" (in generic code, so it
works with pointers too) or a const &.

Should such compile? And why is a builtin type different from a struct
in this context? Thanks.
--Daniel
My guess is a default assignment operator is defined, so f() returns a
temporary, and then operator=(const F &) is invoked on that temporary
with the temporary you constructed with your second F();
 
M

Michael Tsang

Daniel said:
So why does the following compile? (g++ and comeau)
struct F{
int i;
};
F f() { return F();}
void function() {
f()=F();
}

If I replace F with int (or return a pointer pointer), the compiler
gives the expected message that the return of f() is not an l-value.
But it compiles fine as above (just produces unexpected results). This
came up with a class which has operator[] which returns by value and
allowed c[10]=value; to compile, but have no actual effects. I guess
the right solution is to return a "F const" (in generic code, so it
works with pointers too) or a const &.

Should such compile? And why is a builtin type different from a struct
in this context? Thanks.
--Daniel

You can prevent assignment to r-values by passing *this as a l-value
reference:

struct F {
int i;
F &operator=(const F &x) & { // prevent calling from r-value, not sure if
this can be defaulted
i = x.i;
}
};
 
W

White Wolf

Michael said:
Daniel said:
So why does the following compile? (g++ and comeau)
struct F{
int i;
};
F f() { return F();}
void function() {
f()=F();
}

If I replace F with int (or return a pointer pointer), the compiler
gives the expected message that the return of f() is not an l-value.
But it compiles fine as above (just produces unexpected results). This
came up with a class which has operator[] which returns by value and
allowed c[10]=value; to compile, but have no actual effects. I guess
the right solution is to return a "F const" (in generic code, so it
works with pointers too) or a const &.

Should such compile? And why is a builtin type different from a struct
in this context? Thanks.
--Daniel

You can prevent assignment to r-values by passing *this as a l-value
reference:

struct F {
int i;
F &operator=(const F &x) & { // prevent calling from r-value, not sure if
this can be defaulted
i = x.i;
}
};

I am unaware of such syntax in the current standard C++ language. Where
did it come from?
 

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
473,768
Messages
2,569,574
Members
45,050
Latest member
AngelS122

Latest Threads

Top