Topic: lifetime of temporaries bound to references


Author: Dragan Milenkovic <dragan@plusplus.rs>
Date: Wed, 19 May 2010 03:46:52 CST
Raw View
Johannes Schaub (litb) wrote:
>
> Dragan Milenkovic wrote:
>
>> Johannes Schaub (litb) wrote:
>>>
>>> Paul Bibbings wrote:
>>>
>>>> "Johannes Schaub (litb)" <schaub-johannes@web.de> writes:
>>>>>
>>>>> If you read the C++03 and C++0x standard literally, i believe it has to
>>>>> lenthen its lifetime. But that's not the intent. Actually, the Standard
>>>>> says
>>>>>
>>>>> "The lifetime of a temporary bound to the returned value in a function
>>>>> return statement (6.6.3) is not extended; the temporary is destroyed at
>>>>> the end of the full-expression in the return statement."
>>>>>
>>>>> So it actually says the following calls the objects' destructor at the
>>>>> "return *this" after evaluating "*this"
>>>>>
>>>>> struct A { A &f() { return *this; } void g() { } };
>>>>> int main() { A().g(); }
>>>>>
>>>>> That snippet is doing undefined behavior because it calls "g" on a
>>>>> already destroyed object.
>>>>
>>>> <snip />
>>>>
>>>> Just so that I can be sure that I am understanding what you are
>>>> describing here, can I ask, did you perhaps intend the full expression
>>>> in main to read:
>>>>
>>>>  A().f().g();
>>>>
>>>> With this `corrected' reading I can make some sense of your argument,
>>>> but not so without it.
>>>>
>>> Ohh i totally missed to call f. I'm sorry for any confusion caused.
>>
>> "The lifetime of a temporary"... but if you jump to 6.6.3 it says:
>>
>> "A return statement _can_ involve the construction and copy or move
>> of a temporary object (12.2)."
>>
>> And back to 12.2p1 lists only "returning a prvalue" as something that
>> will create a temporary.
>>
>
> But it also lists and says that "A()" is a temporary, and "*this" refers to
> that temporary object. Thus we try to bind a temporary object to "the
> returned value".

My interpretation of the term "temporary object" only applies to
the context of its creation. As we step inside the function f,
*this becomes a lvalue reference, although underneath it indeed refers
to a temporary object. Maybe the Standard should do a better job with
defining the term "temporary object"? Would that clear things up?

(Maybe the Standard already does so, but at least I was unable
to see it.)

--
Dragan

[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Andy Venikov <swojchelowek@gmail.com>
Date: Mon, 10 May 2010 23:37:32 CST
Raw View
Given a following function:

template <typename T>
T const & dummy(T const & in)
{
 return in;
}

will the following code produce a dangling reference:

int const & cr = dummy(5);

???

Reading the wording of the latest draft for C++0x it looks like it will.
[12.1] clause 5, second condition.
Was it the case for c++03 as well?


Thanks,
   Andy.

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Johannes Schaub (litb)" <schaub-johannes@web.de>
Date: Tue, 11 May 2010 15:39:25 CST
Raw View
Andy Venikov wrote:

> Given a following function:
>
> template <typename T>
> T const & dummy(T const & in)
> {
>  return in;
> }
>
> will the following code produce a dangling reference:
>
> int const & cr = dummy(5);
>
> ???
>
> Reading the wording of the latest draft for C++0x it looks like it will.
> [12.1] clause 5, second condition.
> Was it the case for c++03 as well?
>
>

If you read the C++03 and C++0x standard literally, i believe it has to
lenthen its lifetime. But that's not the intent. Actually, the Standard says

"The lifetime of a temporary bound to the returned value in a function
return statement (6.6.3) is not extended; the temporary is destroyed at the
end of the full-expression in the return statement."

So it actually says the following calls the objects' destructor at the
"return *this" after evaluating "*this"

struct A { A &f() { return *this; } void g() { } };
int main() { A().g(); }

That snippet is doing undefined behavior because it calls "g" on a already
destroyed object. In all honesty i don't see how "*this" wouldn't refer to a
temporary object, and thus how the statement couldn't apply. I believe it
needs wording that says all that lifetime stuff at 12.1 only applies for
temporaries not yet bound to references (for this purpose, the implicit
object parameter would be an actual reference binding). This would mean for
your snippet that your temporary object is not lifetime extended and for my
snippet that "*this" is not destroyed prematurely.

In practice you can count that any implementation gets the intent right and
neither does extend lifetime for your snippet nor does end lifetime
prematurely for my snippet.

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use
mailto:std-c++@netlab.cs.rpi.edu<std-c%2B%2B@netlab.cs.rpi.edu>
]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Dragan Milenkovic <dragan@plusplus.rs>
Date: Wed, 12 May 2010 12:10:30 CST
Raw View
Johannes Schaub (litb) wrote:

> Andy Venikov wrote:
>
> Given a following function:
>>
>> template <typename T>
>> T const & dummy(T const & in)
>> {
>>  return in;
>> }
>>
>> will the following code produce a dangling reference:
>>
>> int const & cr = dummy(5);
>>
>> ???
>>
>> Reading the wording of the latest draft for C++0x it looks like it will.
>> [12.1] clause 5, second condition.
>> Was it the case for c++03 as well?
>>
>>
>>
> If you read the C++03 and C++0x standard literally, i believe it has to
> lenthen its lifetime. But that's not the intent. Actually, the Standard
> says
>

I'm pretty confused here. Who has to lengthen what? AFAIK, what dummy
returns is not a temporary object but a reference. It will directly
bind to "cr" and it will dangle after that line is evaluated.

--
Dragan


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use
mailto:std-c++@netlab.cs.rpi.edu<std-c%2B%2B@netlab.cs.rpi.edu>
]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: David Krauss <potswa@gmail.com>
Date: Wed, 12 May 2010 12:10:41 CST
Raw View
On May 11, 12:37 am, Andy Venikov <swojchelo...@gmail.com> wrote:
> will the following code produce a dangling reference:
>
> int const & cr = dummy(5);
>
> Reading the wording of the latest draft for C++0x it looks like it will.
> [12.1] clause 5, second condition.
> Was it the case for c++03 as well?

I think you mean 12.2/5, and it says exactly the same thing as it used
to:

| A temporary bound to a reference parameter in a function call
| (5.2.2) persists until the completion of the full expression
| containing the call.

I seem to recall some language somewhere specifying that temporary
extensions aren't transitive over references, but in any case, the
language specifies a particular destruction time for every temporary
based on the reference to which it is *immediately* bound.


--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use
mailto:std-c++@netlab.cs.rpi.edu<std-c%2B%2B@netlab.cs.rpi.edu>
]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Johannes Schaub (litb)" <schaub-johannes@web.de>
Date: Thu, 13 May 2010 11:29:58 CST
Raw View
Dragan Milenkovic wrote:

> Johannes Schaub (litb) wrote:
>
>> Andy Venikov wrote:
>>
>> Given a following function:
>>>
>>> template <typename T>
>>> T const & dummy(T const & in)
>>> {
>>>  return in;
>>> }
>>>
>>> will the following code produce a dangling reference:
>>>
>>> int const & cr = dummy(5);
>>>
>>> ???
>>>
>>> Reading the wording of the latest draft for C++0x it looks like it will.
>>> [12.1] clause 5, second condition.
>>> Was it the case for c++03 as well?
>>>
>>>
>>>
>> If you read the C++03 and C++0x standard literally, i believe it has to
>> lenthen its lifetime. But that's not the intent. Actually, the Standard
>> says
>>
>
> I'm pretty confused here. Who has to lengthen what? AFAIK, what dummy
> returns is not a temporary object but a reference. It will directly
> bind to "cr" and it will dangle after that line is evaluated.
>

I don't think so: once you evaluate "dummy(5)" you find the expression has
type "int const" and refers to a temporary object (the one created to bind
the reference parameter to the literal).

The wording, i think, needs to explicitly mention that it only applies to
temporaries not yet bound to references but it doesn't. The wording about
optimization of temporaries explicitly mentions that likewise at
12.8/15bullet2. Same about exception objects:

std::string &f(std::string &a) {
 return a;
}

...

try {
 throw std::string("foo");
} catch(std::string &a) {
 f(a);
 std::string x = a; // undefined behavior now!?
}

The wording about exceptions says a temporary is created to store the
exception object while stack is unwound, and that the temporary is an lvalue
(i guess for the purpose of reference binding). Saying that the lifetime-
lengthen rules only apply to temporaries not yet bound to references like
12.8/15 does would also solve this exception-object issue.

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Dragan Milenkovic <dragan@plusplus.rs>
Date: Thu, 13 May 2010 14:08:43 CST
Raw View
Johannes Schaub (litb) wrote:
>
> Dragan Milenkovic wrote:
>
>> Johannes Schaub (litb) wrote:
>>
>>> Andy Venikov wrote:
>>>
>>> Given a following function:
>>>>
>>>> template <typename T>
>>>> T const & dummy(T const & in)
>>>> {
>>>>  return in;
>>>> }
>>>>
>>>> will the following code produce a dangling reference:
>>>>
>>>> int const & cr = dummy(5);
>>>>
>>>> ???
>>>>
>>>> Reading the wording of the latest draft for C++0x it looks like it will.
>>>> [12.1] clause 5, second condition.
>>>> Was it the case for c++03 as well?
>>>>
>>>>
>>>>
>>> If you read the C++03 and C++0x standard literally, i believe it has to
>>> lenthen its lifetime. But that's not the intent. Actually, the Standard
>>> says
>>>
>> I'm pretty confused here. Who has to lengthen what? AFAIK, what dummy
>> returns is not a temporary object but a reference. It will directly
>> bind to "cr" and it will dangle after that line is evaluated.
>>
>
> I don't think so: once you evaluate "dummy(5)" you find the expression has
> type "int const" and refers to a temporary object (the one created to bind
> the reference parameter to the literal).

int global_int;

int const & dummy_1(int const & in) {
   return in;
}

int const & dummy_2(int const & in) {
   return global_int;
}

int const & cr_1 = dummy_1(5);  // #1
int const & cr_2 = dummy_2(5);  // #2

Don't tell me you are saying that #1 and #2 should behave differently.
The only thing that is different is the implementation of dummy_x,
not it's declaration. Nothing (except a potential optimization)
should be defined in terms of dummy_x implementation.

AFAIK neither function returns a temporary, but a lvalue reference
to constant object. Check the very beginning of [class.temporary] which
explains cases that create a temporary object.

Please, anyone, correct me if I'm wrong.

--
Dragan

[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: cpp4ever <n2xssvv.g02gfr12930@ntlworld.com>
Date: Fri, 14 May 2010 15:46:54 CST
Raw View
On 05/11/2010 06:37 AM, Andy Venikov wrote:
> Given a following function:
>
> template <typename T>
> T const & dummy(T const & in)
> {
> return in;
> }
>
> will the following code produce a dangling reference:
>
> int const & cr = dummy(5);
>
> ???
>
> Reading the wording of the latest draft for C++0x it looks like it will.
> [12.1] clause 5, second condition.
> Was it the case for c++03 as well?
>
>
> Thanks,
>   Andy.
>
> --
> [ comp.std.c++ is moderated.  To submit articles, try just posting with ]
> [ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
> [              --- Please see the FAQ before posting. ---               ]
> [ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]
>

Hmmmm,once the original referenced item goes out of scope the reference
surely must be considered invalid, although this does this mean an
exception should occur if you subsequently use the reference? I think
not. If this is a clearer description of what the standard intends, then
I'm glad to have helped.

JB

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Paul Bibbings <paul.bibbings@gmail.com>
Date: Fri, 14 May 2010 15:46:40 CST
Raw View
"Johannes Schaub (litb)" <schaub-johannes@web.de> writes:
> If you read the C++03 and C++0x standard literally, i believe it has to
> lenthen its lifetime. But that's not the intent. Actually, the Standard says
>
> "The lifetime of a temporary bound to the returned value in a function
> return statement (6.6.3) is not extended; the temporary is destroyed at the
> end of the full-expression in the return statement."
>
> So it actually says the following calls the objects' destructor at the
> "return *this" after evaluating "*this"
>
> struct A { A &f() { return *this; } void g() { } };
> int main() { A().g(); }
>
> That snippet is doing undefined behavior because it calls "g" on a already
> destroyed object.

<snip />

Just so that I can be sure that I am understanding what you are
describing here, can I ask, did you perhaps intend the full expression
in main to read:

  A().f().g();

With this `corrected' reading I can make some sense of your argument, but
not so without it.

Regards

Paul Bibbings

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Johannes Schaub (litb)" <schaub-johannes@web.de>
Date: Sat, 15 May 2010 20:15:31 CST
Raw View
Paul Bibbings wrote:

> "Johannes Schaub (litb)" <schaub-johannes@web.de> writes:
>> If you read the C++03 and C++0x standard literally, i believe it has to
>> lenthen its lifetime. But that's not the intent. Actually, the Standard
>> says
>>
>> "The lifetime of a temporary bound to the returned value in a function
>> return statement (6.6.3) is not extended; the temporary is destroyed at
>> the end of the full-expression in the return statement."
>>
>> So it actually says the following calls the objects' destructor at the
>> "return *this" after evaluating "*this"
>>
>> struct A { A &f() { return *this; } void g() { } };
>> int main() { A().g(); }
>>
>> That snippet is doing undefined behavior because it calls "g" on a
>> already destroyed object.
>
> <snip />
>
> Just so that I can be sure that I am understanding what you are
> describing here, can I ask, did you perhaps intend the full expression
> in main to read:
>
>   A().f().g();
>
> With this `corrected' reading I can make some sense of your argument, but
> not so without it.
>
Ohh i totally missed to call f. I'm sorry for any confusion caused.

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Dragan Milenkovic <dragan@plusplus.rs>
Date: Sun, 16 May 2010 22:21:09 CST
Raw View
Johannes Schaub (litb) wrote:
>
> Paul Bibbings wrote:
>
>> "Johannes Schaub (litb)" <schaub-johannes@web.de> writes:
>>>
>>> If you read the C++03 and C++0x standard literally, i believe it has to
>>> lenthen its lifetime. But that's not the intent. Actually, the Standard
>>> says
>>>
>>> "The lifetime of a temporary bound to the returned value in a function
>>> return statement (6.6.3) is not extended; the temporary is destroyed at
>>> the end of the full-expression in the return statement."
>>>
>>> So it actually says the following calls the objects' destructor at the
>>> "return *this" after evaluating "*this"
>>>
>>> struct A { A &f() { return *this; } void g() { } };
>>> int main() { A().g(); }
>>>
>>> That snippet is doing undefined behavior because it calls "g" on a
>>> already destroyed object.
>>
>> <snip />
>>
>> Just so that I can be sure that I am understanding what you are
>> describing here, can I ask, did you perhaps intend the full expression
>> in main to read:
>>
>>  A().f().g();
>>
>> With this `corrected' reading I can make some sense of your argument, but
>> not so without it.
>>
> Ohh i totally missed to call f. I'm sorry for any confusion caused.

"The lifetime of a temporary"... but if you jump to 6.6.3 it says:

"A return statement _can_ involve the construction and copy or move
of a temporary object (12.2)."

And back to 12.2p1 lists only "returning a prvalue" as something that
will create a temporary.

Further, 3.10 explains lvalues, prvalues, etc... with the following
examples:

"As another example, the result of calling a function whose return type
is an lvalue reference is an lvalue"

"The result of calling a function whose return type is not a reference
is a prvalue"

"*this" is not a prvalue but a lvalue, and "return *this" will
not create a temporary.

Back to the questionable text. I believe that it refers to
the following example:

const A & h() { return A(); }

A temporary is created and bound to the returned reference which
will in fact create a dangling reference because the lifetime of
the created temporary object is not extended (which we all know).
I have no idea why is this case covered in such a way - without
mentioning that it is bad for our health. It makes me thing whether
I'm interpreting all this right...

--
Dragan

[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Johannes Schaub (litb)" <schaub-johannes@web.de>
Date: Tue, 18 May 2010 14:01:19 CST
Raw View
Dragan Milenkovic wrote:

> Johannes Schaub (litb) wrote:
>>
>> Paul Bibbings wrote:
>>
>>> "Johannes Schaub (litb)" <schaub-johannes@web.de> writes:
>>>>
>>>> If you read the C++03 and C++0x standard literally, i believe it has to
>>>> lenthen its lifetime. But that's not the intent. Actually, the Standard
>>>> says
>>>>
>>>> "The lifetime of a temporary bound to the returned value in a function
>>>> return statement (6.6.3) is not extended; the temporary is destroyed at
>>>> the end of the full-expression in the return statement."
>>>>
>>>> So it actually says the following calls the objects' destructor at the
>>>> "return *this" after evaluating "*this"
>>>>
>>>> struct A { A &f() { return *this; } void g() { } };
>>>> int main() { A().g(); }
>>>>
>>>> That snippet is doing undefined behavior because it calls "g" on a
>>>> already destroyed object.
>>>
>>> <snip />
>>>
>>> Just so that I can be sure that I am understanding what you are
>>> describing here, can I ask, did you perhaps intend the full expression
>>> in main to read:
>>>
>>>  A().f().g();
>>>
>>> With this `corrected' reading I can make some sense of your argument,
>>> but not so without it.
>>>
>> Ohh i totally missed to call f. I'm sorry for any confusion caused.
>
> "The lifetime of a temporary"... but if you jump to 6.6.3 it says:
>
> "A return statement _can_ involve the construction and copy or move
> of a temporary object (12.2)."
>
> And back to 12.2p1 lists only "returning a prvalue" as something that
> will create a temporary.
>

But it also lists and says that "A()" is a temporary, and "*this" refers to
that temporary object. Thus we try to bind a temporary object to "the
returned value".

> Further, 3.10 explains lvalues, prvalues, etc... with the following
> examples:
>
> "As another example, the result of calling a function whose return type
> is an lvalue reference is an lvalue"
>
> "The result of calling a function whose return type is not a reference
> is a prvalue"
>
> "*this" is not a prvalue but a lvalue, and "return *this" will
> not create a temporary.
>

It doesn't need to create a temporary. The temporary was already created by
the functional cast.

> Back to the questionable text. I believe that it refers to
> the following example:
>
> const A & h() { return A(); }
>
> A temporary is created and bound to the returned reference which
> will in fact create a dangling reference because the lifetime of
> the created temporary object is not extended (which we all know).
> I have no idea why is this case covered in such a way - without
> mentioning that it is bad for our health. It makes me thing whether
> I'm interpreting all this right...
>
Yes, i too think it refers to that example. As i said at the very beginning,
my "interpretation" is pointing to a possible defect of the Standard. I'm
not saying that in my example the object should be destroyed at "return
*this". But i'm saying that the possibly defective text says that.


--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use
mailto:std-c++@netlab.cs.rpi.edu<std-c%2B%2B@netlab.cs.rpi.edu>
]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]