Discussion:
Dangling reference?
(too old to reply)
Matthias Hofmann
2003-12-11 21:21:27 UTC
Permalink
Hello,

I have just read a book about common errors in C++ programs. The following
code demonstrates the error:

const int& max( const int& i1, constint& i2 )
{
return i1 > i2 ? i1 : i2;
}

void f()
{
const int& i = max( 2, 3 );

std::cout << i << std::endl;
}

The book states that a temporary object is created for each parameter to
max(), and that a reference to one of these temporary objects is returned.
However, the book also states that the temporaries will both be destroyed
right after the call to max(), thus creating a dangling reference.

I remember to have read something in the standard that says that the
lifetime of the temporary object is extended to the lifetime of the
reference that is initialized with it, but I am not quite sure.Can anyone
please clarify this for me and tell me wether the book is correct or not?

Best regards,

Matthias Hofmann




[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
John Potter
2003-12-12 09:49:22 UTC
Permalink
On 11 Dec 2003 16:21:27 -0500, "Matthias Hofmann"
Post by Matthias Hofmann
I have just read a book about common errors in C++ programs. The following
const int& max( const int& i1, constint& i2 )
{
return i1 > i2 ? i1 : i2;
}
void f()
{
const int& i = max( 2, 3 );
std::cout << i << std::endl;
}
The book states that a temporary object is created for each parameter to
max(), and that a reference to one of these temporary objects is returned.
However, the book also states that the temporaries will both be destroyed
right after the call to max(), thus creating a dangling reference.
I remember to have read something in the standard that says that the
lifetime of the temporary object is extended to the lifetime of the
reference that is initialized with it, but I am not quite sure.Can anyone
please clarify this for me and tell me wether the book is correct or not?
The book is right. In this case there is nothing to extend. A
temporary copy of 2 and i1 are bound. A temporary copy of 3 and i2 are
bound. No problem, the lifetime of the temporaries is the lifetime of
the statement. Nothing is transitive. I is bound with the return of
the function and then both temporaries are destroyed.

The case you remember is different.

int max (int i1, int i2) { return i1 < i2 ? i2 : i1; }

int const& r = max(2, 3);

Here a temporary copy of the rvalue returned by max is bound to r and
its lifetime is extended to that of r.

In the former, a reference was returned and assumed to live. In the
latter, a value was returned and a temporary was created to live.

John

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Maciej Sobczak
2003-12-12 16:29:27 UTC
Permalink
Hi,
Post by Matthias Hofmann
I have just read a book about common errors in C++ programs. The following
const int& max( const int& i1, constint& i2 )
{
return i1 > i2 ? i1 : i2;
}
void f()
{
const int& i = max( 2, 3 );
I remember to have read something in the standard that says that the
lifetime of the temporary object is extended to the lifetime of the
reference that is initialized with it
and this applies to references that are parameters in the 'max'
function. These references are bound to temporaries and therefore you
can be sure that temporaries will live at least as long as these
references are around.
The problem is that the returned reference *is not* directly bound to
any of the temporaries (it is "further in the chain" of references) and
the rule does not apply here. The temporary goes away and the reference
is dangling.

You may also find similar (and I believe more popular) problem here:

class MyClass
{
public:
MyClass(const int &i) : ref(i) {}
private:
int &ref;
};

int main()
{
MyClass x(7);
// x.ref is dangling at this point
}

Again - the rule about extending the lifetime of the temporary applies
only to the first reference that is bound to it, which is the
constructor's 'i' parameter in the above example. The rule is not
"transitive" for other references that are initialized with previous
ones and so 'ref' member is dangling right after leaving the
constructor, because 'i' reference vanishes itself.
--
Maciej Sobczak : http://www.msobczak.com/
Programming : http://www.msobczak.com/prog/


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Dietmar Kuehl
2003-12-12 16:35:45 UTC
Permalink
Post by Matthias Hofmann
I remember to have read something in the standard that says that the
lifetime of the temporary object is extended to the lifetime of the
reference that is initialized with it, but I am not quite sure.Can anyone
please clarify this for me and tell me wether the book is correct or not?
It is true that binding a temporary to an object will extend the lifetime
of the object until the reference goes out of scope. However, this only
applies if the compiler can see that the temporary is bound to a reference.
In the case where the temporary is passed into a function, the compiler has
no knowledge about a reference to it being returned again. OK, this is
somewhat imprecise but the standardese would be quite complicated and I
think I have accurately captured the intend.
--
<mailto:***@yahoo.com> <http://www.dietmar-kuehl.de/>
Phaidros eaSE - Easy Software Engineering: <http://www.phaidros.com/>

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
k***@gabi-soft.fr
2003-12-12 19:20:15 UTC
Permalink
Post by Matthias Hofmann
I have just read a book about common errors in C++ programs. The
const int& max( const int& i1, constint& i2 )
{
return i1 > i2 ? i1 : i2;
}
void f()
{
const int& i = max( 2, 3 );
std::cout << i << std::endl;
}
The book states that a temporary object is created for each parameter
to max(), and that a reference to one of these temporary objects is
returned. However, the book also states that the temporaries will
both be destroyed right after the call to max(), thus creating a
dangling reference.
I remember to have read something in the standard that says that the
lifetime of the temporary object is extended to the lifetime of the
reference that is initialized with it, but I am not quite sure.Can
anyone please clarify this for me and tell me wether the book is
correct or not?
If a temporary is used to initialize a reference, its lifetime is
extended to that of the reference (but never shorted, if it would
otherwise have a lifetime shorter than that of the reference). This
property isn't transitive, however -- initializing a second reference
with a reference initialized with a temporary doesn't extend the
lifetime of the temporary to that of the second reference.

In your example, the temporary is used to initialize the function
parameter reference; the lifetime of the reference is in fact shorter
than that of the temporary (which lasts until the end of the
expression), so it has no effect on the lifetime of the temporary. The
return value is not initialized by a temporary, but by a reference, and
have no effect on the lifetime of the temporary. Finally, i is
initialized from the reference returned by max, and so has no effect on
the lifetime of the temporary. The lifetime of the temporaries remains
thus until the end of the full expression -- in this case, until the
closing ; of the definition. And after that, the reference i dangles.

--
James Kanze GABI Software mailto:***@gabi-soft.fr
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Loading...