Object lifetimes when bound to references

  • Thread starter Matthias Kaeppler
  • Start date
M

Matthias Kaeppler

Hello,

during a discussion on a C++ internet forum, some question came up
regarding references and the lifetime of the objects they alias.

I can't find any clear wording on that in the draft standard. Example
12.2 in the standard document illustrates that temporaries bound to
references-to-const live as long as the reference does.
But does it e.g. matter if the temporary was created in scope of a
function body and has to outlive the function call? And what happens
with this temporary when everything else from the stack has to be
destroyed except the temporary? Is it copied to a new location in memory?

Examples:

int f1()
{
int a=1;
return a;
}

int& f1r() // note that the return type changed
{
int a=1;
return a;
}

int f2()
{
int a(1),b(2);
return a+b;
}

int& f2r()
{
int a(1),b(2);
return a+b;
}

....
/* 1 */ const int& ref = f1();
/* 2 */ const int& ref = f1r();
/* 3 */ const int& ref = f2();
/* 4 */ const int& ref = f2r();
/* 5-8 */ <like 1-4 but without const qualifier>

Can you comment expressions 1-8 regarding their behavior (defined,
undefined) and the lifetime of the objects which are aliased?

Thanks a lot.
 
V

Victor Bazarov

Matthias said:
I can't find any clear wording on that in the draft standard. Example
12.2 in the standard document illustrates that temporaries bound to
references-to-const live as long as the reference does.

That only refers to a temporary bound _directly_ to a const reference.
But does it e.g. matter if the temporary was created in scope of a
function body and has to outlive the function call?

In a normal execution of the program, a temporary created in the body
of a function cannot outlive the function call. The only way where
a temporary created inside a function can outlive the function by
having a reference bound to it is when an exception is thrown.
And what happens
with this temporary when everything else from the stack has to be
destroyed except the temporary? Is it copied to a new location in
memory?

That's unspecified, IIRC.
Examples:

int f1()
{
int a=1;
return a;
}

int& f1r() // note that the return type changed
{
int a=1;
return a;

Undefined behaviour. You're returning a reference to a local variable.
As soon as the function returns, the reference is invalid.
}

int f2()
{
int a(1),b(2);
return a+b;
}

int& f2r()
{
int a(1),b(2);
return a+b;

Ill-formed. A reference to a non-const object is [attempted to be] bound
to a temporary. Shall not compile (8.5.3/5).
}

...
/* 1 */ const int& ref = f1();
/* 2 */ const int& ref = f1r();
/* 3 */ const int& ref = f2();
/* 4 */ const int& ref = f2r();
/* 5-8 */ <like 1-4 but without const qualifier>

Can you comment expressions 1-8 regarding their behavior (defined,
undefined) and the lifetime of the objects which are aliased?

Cases 1 and 3 have const references bound to temporaries created as
the result of functions returning an object. Those objects live as long
as the references live (in the surrounding scope, which can be as broad
as global). The temporaries are not actually created *inside* the
function.

All other cases either have undefined behavioir because you're returning
a reference to a local object or ill-formed because a non-const reference
cannot be bound to a temporary object.

V
 
M

Matthias Kaeppler

Victor said:
Matthias said:
I can't find any clear wording on that in the draft standard. Example
12.2 in the standard document illustrates that temporaries bound to
references-to-const live as long as the reference does.


That only refers to a temporary bound _directly_ to a const reference.

But does it e.g. matter if the temporary was created in scope of a
function body and has to outlive the function call?


In a normal execution of the program, a temporary created in the body
of a function cannot outlive the function call. The only way where
a temporary created inside a function can outlive the function by
having a reference bound to it is when an exception is thrown.

And what happens
with this temporary when everything else from the stack has to be
destroyed except the temporary? Is it copied to a new location in
memory?


That's unspecified, IIRC.

Examples:

int f1()
{
int a=1;
return a;
}

int& f1r() // note that the return type changed
{
int a=1;
return a;


Undefined behaviour. You're returning a reference to a local variable.
As soon as the function returns, the reference is invalid.

}

int f2()
{
int a(1),b(2);
return a+b;
}

int& f2r()
{
int a(1),b(2);
return a+b;


Ill-formed. A reference to a non-const object is [attempted to be] bound
to a temporary. Shall not compile (8.5.3/5).

}

...
/* 1 */ const int& ref = f1();
/* 2 */ const int& ref = f1r();
/* 3 */ const int& ref = f2();
/* 4 */ const int& ref = f2r();
/* 5-8 */ <like 1-4 but without const qualifier>

Can you comment expressions 1-8 regarding their behavior (defined,
undefined) and the lifetime of the objects which are aliased?


Cases 1 and 3 have const references bound to temporaries created as
the result of functions returning an object. Those objects live as long
as the references live (in the surrounding scope, which can be as broad
as global). The temporaries are not actually created *inside* the
function.

All other cases either have undefined behavioir because you're returning
a reference to a local object or ill-formed because a non-const reference
cannot be bound to a temporary object.

V

Alright, and what if I change the signature of f1r() to

const int& f1r()

and the signature of f2r() to

const int& f2r()

respectively?
 
M

Matthias Kaeppler

Victor said:
That only refers to a temporary bound _directly_ to a const reference.

Do you have the paragaph at hand which backs this statement?
 
V

Victor Bazarov

Matthias said:
Do you have the paragaph at hand which backs this statement?

12.2/5, I believe.

The point of my statement is to say that

const int & i = 5;
const int & j = i;

does not make the temporary '5' persist as long as 'j' lives, only as
long as 'i' lives. IOW, the second initialisation is not "binding of
a temporary to a reference".

V
 
V

Victor Bazarov

Matthias said:
Victor said:
Matthias said:
I can't find any clear wording on that in the draft standard.
Example 12.2 in the standard document illustrates that temporaries bound
to
references-to-const live as long as the reference does.


That only refers to a temporary bound _directly_ to a const
reference.
But does it e.g. matter if the temporary was created in scope of a
function body and has to outlive the function call?


In a normal execution of the program, a temporary created in the body
of a function cannot outlive the function call. The only way where
a temporary created inside a function can outlive the function by
having a reference bound to it is when an exception is thrown.

And what happens
with this temporary when everything else from the stack has to be
destroyed except the temporary? Is it copied to a new location in
memory?


That's unspecified, IIRC.

Examples:

int f1()
{
int a=1;
return a;
}

int& f1r() // note that the return type changed
{
int a=1;
return a;


Undefined behaviour. You're returning a reference to a local
variable. As soon as the function returns, the reference is invalid.

}

int f2()
{
int a(1),b(2);
return a+b;
}

int& f2r()
{
int a(1),b(2);
return a+b;


Ill-formed. A reference to a non-const object is [attempted to be]
bound to a temporary. Shall not compile (8.5.3/5).

}

...
/* 1 */ const int& ref = f1();
/* 2 */ const int& ref = f1r();
/* 3 */ const int& ref = f2();
/* 4 */ const int& ref = f2r();
/* 5-8 */ <like 1-4 but without const qualifier>

Can you comment expressions 1-8 regarding their behavior (defined,
undefined) and the lifetime of the objects which are aliased?


Cases 1 and 3 have const references bound to temporaries created as
the result of functions returning an object. Those objects live as
long as the references live (in the surrounding scope, which can be
as broad as global). The temporaries are not actually created
*inside* the function.

All other cases either have undefined behavioir because you're
returning a reference to a local object or ill-formed because a
non-const reference cannot be bound to a temporary object.

V

Alright, and what if I change the signature of f1r() to

const int& f1r()

and the signature of f2r() to

const int& f2r()

respectively?


As soon as the function returns and the full expression that contains
that funciton call is evaluated, the temporary is going to be destroyed.
So, in f1r a temporary will be created but will only live long enough
to make it to the outside. A reference initialised from that reference
( /* 2 */ const int& ref = f1r(); ) is still going to be invalid (thus
the program has undefined behaviour). The same with case 4.

V
 
V

Victor Bazarov

Matthias said:


Wanted to add that if you wrote

const int& f2r() { int a(1), b(2); return a+b; }

...

const int& ref = f2r() + 0;

you would have a valid and definedly-behaved program because
there would be another temporary created to which 'ref' is bound
and that temporary would persist as long as 'ref' lives.

V
 

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

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,011
Latest member
AjaUqq1950

Latest Threads

Top