469,963 Members | 2,068 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,963 developers. It's quick & easy.

Returned object assigned to reference

Consider the following:

#include <iostream>

struct X
{
int x;
X() { x = 6; }
};

X val()
{
return X();
}

int main()
{
X & x = val();
X x2 = x;
std::cout << x.x << " " << x2.x;
}

What is the lifetime of the object returned by the call to val()? I
would have thought it should be destroyed immediately, creating a
dangling reference, yet the program works, does the returned object
live until the end of it's enclosing scope?

May 1 '06 #1
21 1664
* Andrew Ward:
Consider the following:

#include <iostream>

struct X
{
int x;
X() { x = 6; }
};

X val()
{
return X();
}

int main()
{
X & x = val();
X x2 = x;
std::cout << x.x << " " << x2.x;
}

What is the lifetime of the object returned by the call to val()? I
would have thought it should be destroyed immediately, creating a
dangling reference, yet the program works, does the returned object
live until the end of it's enclosing scope?


Anything, because this is Undefined Behavior.

A reference to const would be another matter.

Then the reference would be valid until the end of the scope.
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
May 1 '06 #2
Could you please explain what you mean by "A reference to const would
be another matter." by modifying the example given.

May 1 '06 #3
* Andrew Ward:
Could you please explain what you mean by "A reference to const would
be another matter." by modifying the example given.


Please quote what you're replying to; I don't know what the heck you're
talking about.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
May 1 '06 #4
Alf P. Steinbach wrote:
* Andrew Ward:
Could you please explain what you mean by "A reference to const would
be another matter." by modifying the example given.


Please quote what you're replying to; I don't know what the heck you're
talking about.


My ISP has just recently decided to stop providing a usenet server, so
as I have not found another server to use yet I posted that message
from google groups, and assumed it would automatically quote you,
apparently not.

May 1 '06 #5
Alf P. Steinbach wrote:
* Andrew Ward:
X val() { return X(); }

int main()
{
X & x = val();

What is the lifetime of the object returned by the call to val()? I
would have thought it should be destroyed immediately, creating a
dangling reference, yet the program works, does the returned object
live until the end of it's enclosing scope?
Anything, because this is Undefined Behavior.


Is a diagnostic required?
A reference to const would be another matter.
Then the reference would be valid until the end of the scope.


To answer the question asked by the OP in a poorly-written
reply:

X const &x = val();

would not lead to undefined behaviour, and the lifetime of
the temporary object is extended to match the lifetime
of the reference.

May 2 '06 #6
* Old Wolf:
Alf P. Steinbach wrote:
* Andrew Ward:
X val() { return X(); }

int main()
{
X & x = val();

What is the lifetime of the object returned by the call to val()? I
would have thought it should be destroyed immediately, creating a
dangling reference, yet the program works, does the returned object
live until the end of it's enclosing scope?

Anything, because this is Undefined Behavior.


Is a diagnostic required?


Undefined Behavior does not require a diagnostic: it's Undefined what
happens... ;-)

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
May 2 '06 #7
* Alf P. Steinbach:
* Old Wolf:
Alf P. Steinbach wrote:
* Andrew Ward:
X val() { return X(); }

int main()
{
X & x = val();

What is the lifetime of the object returned by the call to val()? I
would have thought it should be destroyed immediately, creating a
dangling reference, yet the program works, does the returned object
live until the end of it's enclosing scope?
Anything, because this is Undefined Behavior.


Is a diagnostic required?


Undefined Behavior does not require a diagnostic: it's Undefined what
happens... ;-)


Hey, wait, that's true, but the function doesn't return a reference.

So it's not UB, it's simply something that should not compile (i.e. a
diagnostic is required).

I thought this was something that compiled.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
May 2 '06 #8
Alf P. Steinbach wrote:
* Alf P. Steinbach:
* Old Wolf:
Alf P. Steinbach wrote:
* Andrew Ward:
> X val() { return X(); }
>
> int main()
> {
> X & x = val();
>
> What is the lifetime of the object returned by the call to val()? I
> would have thought it should be destroyed immediately, creating a
> dangling reference, yet the program works, does the returned object
> live until the end of it's enclosing scope?
Anything, because this is Undefined Behavior.

Is a diagnostic required?


Undefined Behavior does not require a diagnostic: it's Undefined what
happens... ;-)


Hey, wait, that's true, but the function doesn't return a reference.

So it's not UB, it's simply something that should not compile (i.e. a
diagnostic is required).

I thought this was something that compiled.


Thanks both of you for your replies. If I understand correctly it would
be a compiler bug if the original posted code compiled without error.
This is the case with VS 2003 and 2005. But GCC 3.3.5 reports the error
correctly with this message:
error: invalid initialization of non-const reference of type 'X&' from
temporary of type 'X'

May 2 '06 #9
Alf P. Steinbach wrote:
* Alf P. Steinbach:
* Old Wolf:
Alf P. Steinbach wrote:
* Andrew Ward:
> X val() { return X(); }
>
> int main()
> {
> X & x = val();
>
> What is the lifetime of the object returned by the call to val()? I
> would have thought it should be destroyed immediately, creating a
> dangling reference, yet the program works, does the returned object
> live until the end of it's enclosing scope?
Anything, because this is Undefined Behavior.

Is a diagnostic required?


Undefined Behavior does not require a diagnostic: it's Undefined what
happens... ;-)


Hey, wait, that's true, but the function doesn't return a reference.

So it's not UB, it's simply something that should not compile (i.e. a
diagnostic is required).

I thought this was something that compiled.


I thought this was legal and a temporary copy of X was returned from
val() to satisfy the rhs of operator=(). Is this not so?

Dave.

May 2 '06 #10
ra*********@gmail.com wrote:
Alf P. Steinbach wrote:
* Alf P. Steinbach:
* Old Wolf:
> Alf P. Steinbach wrote:
>> * Andrew Ward:
>>> X val() { return X(); }
>>>
>>> int main()
>>> {
>>> X & x = val();
>>>
>>> What is the lifetime of the object returned by the call to val()? I
>>> would have thought it should be destroyed immediately, creating a
>>> dangling reference, yet the program works, does the returned object
>>> live until the end of it's enclosing scope?
>> Anything, because this is Undefined Behavior.
>
> Is a diagnostic required?

Undefined Behavior does not require a diagnostic: it's Undefined what
happens... ;-)


Hey, wait, that's true, but the function doesn't return a reference.

So it's not UB, it's simply something that should not compile (i.e. a
diagnostic is required).

I thought this was something that compiled.


I thought this was legal and a temporary copy of X was returned from
val() to satisfy the rhs of operator=(). Is this not so?


No. val() returns an rvalue and it is bound to a non-const reference,
which is illegal. With

X& val() // <-- reference
{
return X(); // <-- rvalue
}

int main()
{
X& x = val(); // <-- ok
}

the assignment would compile (though having undefined behavior), but
then the return statement would not compile (X() is an rvalue, so the
same problem arises). Finally,

X& val() // <-- reference
{
X x;
return x; // <-- lvalue
}

int main()
{
X& x = val(); // <-- undefined behavior
}

would compile fine, but you'd get undefined behavior because val()
returns a reference to a local object (destroyed at the end of val()).
One way to make this work would be to return a reference and to assign
it to a const reference, extending the life of X() to match the
reference's:

X val() // <-- rvalue
{
return X(); // <-- rvalue
}

int main()
{
const X& x = val(); // ok, const-ref bound to rvalue
}

To be able to modify the object, you must copy it:

int main()
{
X x = val(); // ok
}
Jonathan

May 2 '06 #11
Jonathan Mcdougall wrote:
ra*********@gmail.com wrote:
Alf P. Steinbach wrote:
* Alf P. Steinbach:
* Old Wolf:
> Alf P. Steinbach wrote:
>> * Andrew Ward:
>>> X val() { return X(); }
>>>
>>> int main()
>>> {
>>> X & x = val();
>>>
>>> What is the lifetime of the object returned by the call to
>>> val()? I would have thought it should be destroyed immediately,
>>> creating a dangling reference, yet the program works, does the
>>> returned object live until the end of it's enclosing scope?
>> Anything, because this is Undefined Behavior.
>
> Is a diagnostic required?

Undefined Behavior does not require a diagnostic: it's Undefined
what happens... ;-)

Hey, wait, that's true, but the function doesn't return a reference.

So it's not UB, it's simply something that should not compile (i.e.
a diagnostic is required).

I thought this was something that compiled.
I thought this was legal and a temporary copy of X was returned from
val() to satisfy the rhs of operator=(). Is this not so?


No. val() returns an rvalue and it is bound to a non-const reference,
which is illegal. With

X& val() // <-- reference
{
return X(); // <-- rvalue
}

int main()
{
X& x = val(); // <-- ok
}

the assignment would compile (though having undefined behavior), but
then the return statement would not compile (X() is an rvalue, so the
same problem arises). Finally,

X& val() // <-- reference
{
X x;
return x; // <-- lvalue
}

int main()
{
X& x = val(); // <-- undefined behavior
}

would compile fine, but you'd get undefined behavior because val()
returns a reference to a local object (destroyed at the end of val()).
One way to make this work would be to return a reference


[Ahem]... "to return an _object_"
and to assign
it to a const reference,
"and initialise a reference to const with it"
extending the life of X() to match the
reference's:

X val() // <-- rvalue
{
return X(); // <-- rvalue
}

int main()
{
const X& x = val(); // ok, const-ref bound to rvalue
}

To be able to modify the object, you must copy it:

int main()
{
X x = val(); // ok
}


V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
May 2 '06 #12
Alf P. Steinbach wrote:
* Old Wolf:
Alf P. Steinbach wrote:
* Andrew Ward:
> X val() { return X(); }
>
> int main()
> {
> X & x = val();
>
this is Undefined Behavior.

Is a diagnostic required?


So it's not UB, it's simply something that should not compile (i.e. a
diagnostic is required).


..... hence causing UB due to the constraint violation. But some
UBs don't require a diagnostic. In fact the text I was looking for is
in 1.4#8:

Implementations are required to diagnose programs
that use such extensions that are ill-formed
according to this International Standard.

The standard does not actually say "binding a temporary to a
non-const reference causes UB". It just says that a temporary
may be bound to a const reference, and does not comment on
the notion of binding a temporary to a non-const reference at all.

Hence the attempt to bind a temporary to a non-const reference
is not well-formed since no rule allows it.

May 3 '06 #13
Jonathan Mcdougall wrote:

X val() // <-- rvalue
{
return X(); // <-- rvalue
}

int main()
{
const X& x = val(); // ok, const-ref bound to rvalue
}

To be able to modify the object, you must copy it:


I think it is legal to modify it with a const-cast:

X &y = const_cast<X &>(x);

Temporary objects are not const per se.

May 3 '06 #14
Old Wolf wrote:
Jonathan Mcdougall wrote:

X val() // <-- rvalue
{
return X(); // <-- rvalue
}

int main()
{
const X& x = val(); // ok, const-ref bound to rvalue
}

To be able to modify the object, you must copy it:


I think it is legal to modify it with a const-cast:

X &y = const_cast<X &>(x);

Temporary objects are not const per se.


Correct, although this is not something I would do myself, there`s
some... elegance missing here :) But as long as an object wasn't
declared as const, you may modify it. Note that this applies to
objects, but built-in types are not objects, so this:

const int& i = 8;
const_cast<int&>(i) = 2;

is undefined behavior, but

class X
{
public:
void f();
};

const X& x = X();
const_cast<X&>(x).f();

is perfectly well-defined.

Jonathan

May 3 '06 #15
* Old Wolf:
Alf P. Steinbach wrote:
* Old Wolf:
Alf P. Steinbach wrote:
> * Andrew Ward:
>> X val() { return X(); }
>>
>> int main()
>> {
>> X & x = val();
>>
> this is Undefined Behavior.
Is a diagnostic required? So it's not UB, it's simply something that should not compile (i.e. a
diagnostic is required).


.... hence causing UB due to the constraint violation.


That would be nice because it would support what I originally wrote, but
for the case of a language extension what we have is presumably
unspecified behavor. Unspecified means defined by the implementation,
and an extension is defined by the implementation. Also, this view is
supported by the requirement of a diagnostic (see below).

But some UBs don't require a diagnostic.
No UB requires a diagnostic. It's mentioned first in 1.3.2, that the
permissible UB effect is "with or without the issuance of a diagnostic
message". Then it's mentioned again in 1.4/1, that diagnosable rules do
not include those described as "undefined behavior".

In fact the text I was looking for is in 1.4#8:

Implementations are required to diagnose programs
that use such extensions that are ill-formed
according to this International Standard.
Yep, I think that's the clincher: the OPs code, when interpreted as
using a language extension, has unspecified, not undefined, behavior.

The standard does not actually say "binding a temporary to a
non-const reference causes UB". It just says that a temporary
may be bound to a const reference, and does not comment on
the notion of binding a temporary to a non-const reference at all.

Hence the attempt to bind a temporary to a non-const reference
is not well-formed since no rule allows it.


--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
May 3 '06 #16
Alf P. Steinbach wrote:
But some UBs don't require a diagnostic.


No UB requires a diagnostic.


Do you have any text to support that? (The passages you quote
don't)

This UB requires a diagnostic:
int const i = 5;
i = 6;
In fact the text I was looking for is in 1.4#8:

Implementations are required to diagnose programs
that use such extensions that are ill-formed
according to this International Standard.


Yep, I think that's the clincher: the OPs code, when interpreted as
using a language extension, has unspecified, not undefined, behavior.


The program's behaviour is not defined by the standard,
so it is undefined. Unspecified means that the standard
defines a finite number of possibilities, exactly one of which
must occur.

May 3 '06 #17
Old Wolf wrote:
Alf P. Steinbach wrote:
But some UBs don't require a diagnostic.
No UB requires a diagnostic.


Do you have any text to support that? (The passages you quote
don't)


"1.3.13 undefined behavior

behavior, such as might arise upon use of an erroneous program
construct or erroneous data, for which this International Standard
imposes no requirements. Undefined behavior may also be expected when
this International Standard omits the description of any explicit
definition of behavior. [Note: permissible undefined behavior ranges
from ignoring the situation completely with unpredictable results, to
behaving during translation or program execution in a documented manner
characteristic of the environment (with or without the issuance of a
diagnostic message), to terminating a translation or execution (with
the issuance of a diagnostic message). Many erroneous program
constructs do not engender undefined behavior; they are required to be
diagnosed. -end note]"
This UB requires a diagnostic:
int const i = 5;
i = 6;


No, this is an illegal construct and so requires a diagnostic. This

int *p = 0;
*p = 10;

is a legal construct but has undefined behavior, thus requiring no
diagnostic.
Jonathan

May 3 '06 #18
Jonathan Mcdougall wrote:
Old Wolf wrote:
Alf P. Steinbach wrote:
> But some UBs don't require a diagnostic.

No UB requires a diagnostic.
Do you have any text to support that? (The passages you quote
don't)


"1.3.13 undefined behavior

behavior, such as might arise upon use of an erroneous program
construct or erroneous data, for which this International Standard
imposes no requirements. Undefined behavior may also be expected when
this International Standard omits the description of any explicit
definition of behavior. [Note: permissible undefined behavior ranges
from ignoring the situation completely with unpredictable results, to
behaving during translation or program execution in a documented manner
characteristic of the environment (with or without the issuance of a
diagnostic message), to terminating a translation or execution (with
the issuance of a diagnostic message). Many erroneous program
constructs do not engender undefined behavior; they are required to be
diagnosed. -end note]"


That text doesn't say that no UB requires a diagnostic.
int *p = 0;
*p = 10;

is a legal construct but has undefined behavior, thus requiring no
diagnostic.


The standard doesn't say UB(X) --> ~D(X), as far as I can see.
No diagnostic is required because the standard does not say
that a diagnostic is required (regardless of whether or not the
behaviour is undefined).
This UB requires a diagnostic:
int const i = 5;
i = 6;

No, this is an illegal construct and so requires a diagnostic.


Yes, and it also has undefined behaviour.
My code violates the syntax or constraints of the C++
language, therefore it is not a valid C++ program, therefore
the C++ standard does not define its semantics.

So how can you say that the behaviour is not undefined?

In fact the C++ standard imposes no requirements on my
code (because it is not a valid C++ program). That is
exactly the definition of UB that you quoted above.

Here is a link to a thread on the same topic for the
C language; I presume that C++ treats UB in a
similar way:

http://groups.google.com/group/comp....55babe6c16bb85

May 3 '06 #19
* Old Wolf:
Jonathan Mcdougall wrote:
Old Wolf wrote:
Alf P. Steinbach wrote:

> But some UBs don't require a diagnostic.
No UB requires a diagnostic.
Do you have any text to support that? (The passages you quote
don't)

"1.3.13 undefined behavior

behavior, such as might arise upon use of an erroneous program
construct or erroneous data, for which this International Standard
imposes no requirements. Undefined behavior may also be expected when
this International Standard omits the description of any explicit
definition of behavior. [Note: permissible undefined behavior ranges
from ignoring the situation completely with unpredictable results, to
behaving during translation or program execution in a documented manner
characteristic of the environment (with or without the issuance of a
diagnostic message), to terminating a translation or execution (with
the issuance of a diagnostic message). Many erroneous program
constructs do not engender undefined behavior; they are required to be
diagnosed. -end note]"


That text doesn't say that no UB requires a diagnostic.


It does.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
May 4 '06 #20
Alf P. Steinbach wrote:
* Old Wolf:
That text doesn't say that no UB requires a diagnostic.


It does.


It doesn't. Here's how I read it:
"1.3.13 undefined behavior

behavior, such as might arise upon use of an erroneous program
construct or erroneous data, for which this International Standard
imposes no requirements.
1. If the standard imposes no requirements on X, then X has UB.
2. Use of an erroneous program construct or erroneous data is
an example of UB.
Undefined behavior may also be expected when this International
Standard omits the description of any explicit definition of behavior.
3. If the standard does not explicitly define the behaviour of X,
then X has UB.
[Note: permissible undefined behavior ranges from ignoring the
situation completely with unpredictable results, to behaving
during translation or program execution in a documented manner
characteristic of the environment (with or without the issuance of a
diagnostic message), to terminating a translation or execution (with
the issuance of a diagnostic message).
4. If X is UB, then X may have those effects.
Many erroneous program constructs do not engender undefined
behavior; they are required to be diagnosed. -end note]"


5. There are some program constructs P such that
P does not cause undefined behaviour.

6. If P is an erroneous construct that does not cause
UB, then P requires a diagnostic.

Also the use of 'Many' instead of 'All' implies:

7. There are some program constructs Q such that
Q causes undefined behaviour.

Which part of that do you think corresponds to "no UB
requires a diagnostic" ?

Also, let's not lose sight of the original topic, which is:

Does an ill-formed program have undefined behaviour?

You are arguing "No" (otherwise it would be a program that
requires a diagnostic, and has undefined behaviour, which
you say cannot exist).

So what happens when you run an executable generated
by a compiler that was presented with an ill-formed program?
(which is permitted by (4) above).

The C++ standard imposes no requirements on the
program, therefore by (1) above, the program has undefined
behaviour. Also, by (4) above, the program can have
unpredictable results.

How can you say that the behaviour is anything other
than undefined? It certainly isn't unspecified (which means
the standard imposes a finite number of possible outcomes),
nor is it implementation-defined (like unspecified,
but the implementation must also document which outcome
occurs).

May 4 '06 #21
* Old Wolf:
Alf P. Steinbach wrote:
* Old Wolf:
That text doesn't say that no UB requires a diagnostic. It does.


It doesn't. Here's how I read it:
"1.3.13 undefined behavior

behavior, such as might arise upon use of an erroneous program
construct or erroneous data, for which this International Standard
imposes no requirements.
1. If the standard imposes no requirements on X, then X has UB.


Uh oh. That might well be true, but it isn't what the above quote says.
It says "behavior ... for which this International Standard imposes
no requirements", and that means: this International Standard imposes no
requirements on the behavior.

I.e., the implementation can do anything, or nothing.

2. Use of an erroneous program construct or erroneous data is
an example of UB.
Can be an example, not /is/.

Undefined behavior may also be expected when this International
Standard omits the description of any explicit definition of behavior.
3. If the standard does not explicitly define the behaviour of X,
then X has UB.


No, it's a bit weaker: "may also be expected".

[Note: permissible undefined behavior ranges from ignoring the
situation completely with unpredictable results, to behaving
during translation or program execution in a documented manner
characteristic of the environment (with or without the issuance of a
diagnostic message), to terminating a translation or execution (with
the issuance of a diagnostic message).
4. If X is UB, then X may have those effects.


Yes.

And that means (which also point 1 means), there is no requirement of a
diagnostic.

Relevant words: "no requirements" in point 1, and "ignoring" and
"without" in this point.

Many erroneous program constructs do not engender undefined
behavior; they are required to be diagnosed. -end note]"


5. There are some program constructs P such that
P does not cause undefined behaviour.


Yes.

6. If P is an erroneous construct that does not cause
UB, then P requires a diagnostic.
That's a reasonable interpretation and I tend to concur.

Also the use of 'Many' instead of 'All' implies:

7. There are some program constructs Q such that
Q causes undefined behaviour.
Yes, and for those that are UB, the phrase "they are required to be
diagnosed" doesn't apply; it applies to those that do not "engender
undefined behavior".

Which part of that do you think corresponds to "no UB
requires a diagnostic" ?
All of it. ;-)

Also, let's not lose sight of the original topic, which is:

Does an ill-formed program have undefined behaviour?

You are arguing "No" (otherwise it would be a program that
requires a diagnostic, and has undefined behaviour, which
you say cannot exist).

So what happens when you run an executable generated
by a compiler that was presented with an ill-formed program?
(which is permitted by (4) above).

The C++ standard imposes no requirements on the program


No, that's not the case.

The requirements on the effect of use of a language extension are
discussed in 1.4/8.

Those requirements include that a diagnostic must be issued.
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
May 4 '06 #22

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

2 posts views Thread by Aaron | last post: by
26 posts views Thread by yb | last post: by
12 posts views Thread by Andrew Poulos | last post: by
45 posts views Thread by bigdadro | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.