Sign in to follow this  
neverland

reference and const-reference question

Recommended Posts

consider the following code:
class X {
};

X f() 
{
	return X(); 
}
void g1(X& x) 
{}
void g2(const X& x) 
{}

int main()
{
	g1(f());
	g2(f());

	return 0;
}
I know that reference to a local object is bad. But function g2() is successfully compiled while g1() not. Why ?

Share this post


Link to post
Share on other sites
RETURNING a reference to a local object is bad. Accepting a local object by reference is OK (well, usually - storing the reference in a class of unspecified scope - e.g. newed - is bad mojo too).

Here's what's happening:

f() returns a temporary class by value, X. Because it's a temporary, it's considered constant. g1(f()) fails to compile because you're trying to have a reference to a non constant (in other words, a reference to a mutable object) when the temporary is constant (not mutable).

Basically, it's to catch against weird things like this which don't make sense:

int f() {
return 4;
}

void g1( int & i ) {
i = 5;
}

g1( f() ); //what does this do?


If you don't need to actually modify i, then you simply make g1 accept a reference to a constant:

void int f() {
return 4;
}

void g1( const int & i ) {
std::cout << i << std::endl;
}

g1( f() ); //this prints out 4

Share this post


Link to post
Share on other sites
MaulingMonkey isn't quite right. The problem is that f() returns an r-value and the type X doesn't define an implicit conversion to an l-value compatible with an X reference.

To clarify: In C++ everything is either an r-value or an l-value. When you return an object of class type by value from a function, the returned object is considered to be an r-value. If you have a r-value you can only bind a non-volatile const reference to it, unless the class type defines a conversion to a compatible l-value, like a reference. For example, if X was instead defined like:

class X {
public:
operator X &() { return *this; }
};

Then both function calls should compile since the X type defined an implicit conversion to an l-value. Keep in mind that this conversion operator is non-const. This works because temporaries are not necessarily const. Consider this code:

class X {
public:
void not_const(void) { std::cout << "non const function" << std::endl; }
};

X f() {
return X();
}

int main(int, char **) {
f().not_const();

return 0;
}

This shows more explicitly that a non-const function can be called on a temporary object.

Share this post


Link to post
Share on other sites
Quote:
Original post by MaulingMonkey
Quote:
Original post by SiCrane
MaulingMonkey isn't quite right.

Thanks for clarifying, this is what I get for self-teaching...
I thought your explanations were both great.
Newbies often don't have a clue what an l-value or r-value is though anyway.

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