temporaries and const&

D

dragoncoder

Hi everyone, please consider the following function:-

const int& foo ( const double& d )
{
return d;
}

g++ compiles it with warnings and solaris CC gives error. I want to
know if the code is correct according to the standard ?

/P
 
A

Alf P. Steinbach

* dragoncoder:
Hi everyone, please consider the following function:-

const int& foo ( const double& d )
{
return d;
}

g++ compiles it with warnings and solaris CC gives error. I want to
know if the code is correct according to the standard ?

It's technically correct.

In the return expression an "int const&" reference is bound to
(initialized with) a temporary "int" that's initialized with the
"double", which is implicitly converted to int.

However, using the result of a call to foo() yields Undefined Behavior,
because you're returning a reference to a temporary. C++ is like that,
very permissive by default. It cheerfully lets you shoot yourself in
the groin, instead of arresting you[1], if that's what you say you want.

Cheers,

- Alf


Notes:
[1] <url: http://news.bbc.co.uk/1/hi/england/south_yorkshire/3891311.stm>.
 
V

Victor Bazarov

dragoncoder said:
Hi everyone, please consider the following function:-

const int& foo ( const double& d )
{
return d;
}

g++ compiles it with warnings and solaris CC gives error. I want to
know if the code is correct according to the standard ?

It's "correct", lexically and syntactically. The problem is that
the whole thing is useless because returning by a reference to const
will cause creation of a temporary object, which will survive only
until the end the call to 'foo'. IOW right after the function
returns the temporary object has already been destroyed.

V
 
D

dragoncoder

* dragoncoder:
Hi everyone, please consider the following function:-
const int& foo ( const double& d )
{
return d;
}
g++ compiles it with warnings and solaris CC gives error. I want to
know if the code is correct according to the standard ?

It's technically correct.

In the return expression an "int const&" reference is bound to
(initialized with) a temporary "int" that's initialized with the
"double", which is implicitly converted to int.

However, using the result of a call to foo() yields Undefined Behavior,
because you're returning a reference to a temporary. C++ is like that,
very permissive by default. It cheerfully lets you shoot yourself in
the groin, instead of arresting you[1], if that's what you say you want.

Thanks for the response. In the same context, does this code invoke
undefined behaviour ?

#include <iostream>

template <class T1, class T2>
const T1& max ( const T1& a, const T2& b )
{
return ( a > b ) ? a : b;
}

int main() {
int i = 20; double d = 40;
std::cout << max ( i, d ) << std::endl;
return 0;
}
 
A

Alf P. Steinbach

* dragoncoder:
Thanks for the response. In the same context, does this code invoke
undefined behaviour ?

#include <iostream>

template <class T1, class T2>
const T1& max ( const T1& a, const T2& b )
{
return ( a > b ) ? a : b;
}

int main() {
int i = 20; double d = 40;
std::cout << max ( i, d ) << std::endl;
return 0;
}

Yep. It would be less clear-cut if both arguments were "int const&".
I'd have to read the standard's fine print about the ?:-operator to
figure that out, but I think that when the types are identical reference
types it can produce a reference result, thus no UB in that case.

For more information about how to produce a macro-like templated max
function, see Andrei Alexandrescu's "min and max redivivus" article in
DDJ April 2003, <url: http://www.ddj.com/dept/cpp/184403774>.

The standard library's templated max function just puts the burden on
the programmer, and assumes both arguments are the same type.
 
S

Salt_Peter

Hi everyone, please consider the following function:-

const int& foo ( const double& d )
{
return d;

}

g++ compiles it with warnings and solaris CC gives error. I want to
know if the code is correct according to the standard ?

/P

Sorry but g++ -pedantic -Wall generates 2 warnings:
warning: converting to 'const int' from 'const double'
warning: returning reference to temporary

You should be using static_cast and returning by value, not be
reference, for obvious reasons.
Even so an integer is an integer and a double a double.
 
D

dragoncoder

* dragoncoder:









Yep. It would be less clear-cut if both arguments were "int const&".
I'd have to read the standard's fine print about the ?:-operator to
figure that out, but I think that when the types are identical reference
types it can produce a reference result, thus no UB in that case.

I am a bit confused now. Are you saying it is a case of UB because the
temporary is being accessed after the function call ? That being the
case a simple function like below will also invoke UB ? Am I right ?

const int& bar ( ) { return 10; }

std::cout << bar() << std::endl;

Please enlighten me. Thanks again.
 
A

Alf P. Steinbach

* dragoncoder:
I am a bit confused now. Are you saying it is a case of UB because the
temporary is being accessed after the function call ?

Yes.

The temporary no longer exists at the point where it's used.

Or, in practice it may still exist, but in practice it may also have
been overwritten.

That being the
case a simple function like below will also invoke UB ? Am I right ?
Yes.


const int& bar ( ) { return 10; }

std::cout << bar() << std::endl;

Please enlighten me.

<url:
http://www.amazon.com/Computer-Parables-Enlightenment-Information-Age/dp/0931137136>.

Hm, I'd better buy that book, and quite a few others!

Can't go on recommending books I've never even read (I only have two C++
books, namely TCPPPL in 1st and 2nd edition, the 3rd edition on
permanent load to someone I don't know, and Modern C++ Design, yet I go
on recommending Accelerated C++, C++ Primer, You Can Do It!, etc.).

Thanks again.

You're welcome.
 
J

James Kanze

Hi everyone, please consider the following function:-
const int& foo ( const double& d )
{
return d;
}
g++ compiles it with warnings and solaris CC gives error. I want to
know if the code is correct according to the standard ?

Formally, it's undefined behavior if you use the return value in
any way. If you don't use the return value, I'm not 100% sure,
but if you're never going to use the return value, what's the
point?

As undefined behavior, a compiler is not required to give a
message. In addition, in this case, the undefined behavior only
occurs if you actually execute the statement (or maybe only if
you actually use the return value); formally, a compiler is
required to compile the code unless it can prove that the
function will actually be called. (Practically, of course, I
have no problem with a compiler declaring it an error, and
refusing to compile the code. What's the point in compiling a
function that you cannot legally call?)
 
J

James Kanze

I'm not even sure about that. I "think" the intent is that
copying a dangling reference is undefined behavior (since the
intent is that references can be implemented as pointers, and
copying a dangling pointer is undefined behavior). And
formally, you copy the reference in the return statement,
*after* having "destructed" the local variables.

In practice, of course, even on a machine where copying dangling
pointers does cause a crash, it will work, because in practice, the
return value will be moved to its final location (probably a
register) before the memory on the stack is freed. So any
undefined behavior (if there is some) if you don't use the
return value is purely theoretical.
In the return expression an "int const&" reference is bound to
(initialized with) a temporary "int" that's initialized with the
"double", which is implicitly converted to int.
However, using the result of a call to foo() yields Undefined Behavior,
because you're returning a reference to a temporary. C++ is like that,
very permissive by default. It cheerfully lets you shoot yourself in
the groin, instead of arresting you[1], if that's what you say you want.
Thanks for the response. In the same context, does this code invoke
undefined behaviour ?
#include <iostream>
template <class T1, class T2>
const T1& max ( const T1& a, const T2& b )
{
return ( a > b ) ? a : b;

}
int main() {
int i = 20; double d = 40;
std::cout << max ( i, d ) << std::endl;
return 0;
}

Yes, although I almost missed it. That's a very bad definition
for max. Try:

template< typename T >
T const&
max( T const& a, T const& b )
{
return a > b ? a : b ;
}

You want the type conversion before calling the function, and in
cases of ambiguities like this one, you want the user to
explicitly specify what he wants, and not just automatically
take the type of the first argument.
 
J

James Kanze

* dragoncoder:
Yep. It would be less clear-cut if both arguments were "int const&".
I'd have to read the standard's fine print about the ?:-operator to
figure that out, but I think that when the types are identical reference
types it can produce a reference result, thus no UB in that case.

If both types are lvalues, and neither type requires a
conversion, the result is an lvalue. Thus, no temporary.
For more information about how to produce a macro-like templated max
function, see Andrei Alexandrescu's "min and max redivivus" article in
DDJ April 2003, <url:http://www.ddj.com/dept/cpp/184403774>.
The standard library's templated max function just puts the burden on
the programmer, and assumes both arguments are the same type.

Which is really what you want (although I think Andrei's
solution does try to find the best type, for some definition of
best, instead of arbitrarily using the first type).
 
D

davidrubin

It's "correct", lexically and syntactically. The problem is that
the whole thing is useless because returning by a reference to const
will cause creation of a temporary object, which will survive only
until the end the call to 'foo'. IOW right after the function
returns the temporary object has already been destroyed.

I am under the impression that temporaries assigned to const
references are required to live as long as the reference.

However, wrt OP, I happen to know that Sun CC (Studio8) defaults to
non-standard behavior wrt the lifespan of temporaries. By default
temporaries live until the end of the block they are created in.
However, turning on standard behavior (-features=tmplife) is actually
broken because temporaries assigned to const refefrences are destroyed
before the reference is destroyed.
 
V

Victor Bazarov

I am under the impression that temporaries assigned to const
references are required to live as long as the reference.

That's correct. But this is one of two special cases mentioned in the
Standard. See 12.2/5, "The temporary bound to the returned value in
a function return statement (6.6.3) persists until the function exits."

V
 
J

James Kanze

I am under the impression that temporaries assigned to const
references are required to live as long as the reference.

That's false. A temporary which is used to initialize a const
reference has its lifetime extended (never shorted) to
correspond to that of the const reference it initializes. That
doesn't help here, since the formal semantics of a return
statement are to construct a return value of the correct type,
then destruct all local variables, then *copy* the return value
to where ever return values are returned. (After the return, of
course, the calling code then uses whatever was returned.) The
temporary here is used to initialize this first return value
reference, whose lifetime ends at the end of the function.
However, wrt OP, I happen to know that Sun CC (Studio8)
defaults to non-standard behavior wrt the lifespan of
temporaries. By default temporaries live until the end of the
block they are created in. However, turning on standard
behavior (-features=tmplife) is actually broken because
temporaries assigned to const refefrences are destroyed before
the reference is destroyed.

Funny, I regularly use this option with Sun CC, and I've never
had any problem with it. (On the other hand, it's entirely
possible that I've no code, anywhere, which uses the extended
lifetime. It's only useful in very rare cases.)
 

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,297
Messages
2,571,529
Members
48,250
Latest member
Bette22B13

Latest Threads

Top