My original example is complex.
Therefore I post here a simpler example and I provide the corresponding ISO C++ standard paragraph.
This simpler example is also available on coliru.stacked-crooked.com/
#include <iostream>
struct A
{
A(int i) { std::cout<<"Cstr "<< i<<'\n'; p = new int(i); }
~A() { std::cout<<"Dstr "<<*p<<'\n'; delete p; }
const A& thiz() const { return *this; }
int *p;
};
const A& constref( const A& a )
{
return a;
}
int main()
{
const A& a4 = A(4);
const A& a5 = A(5).thiz();
const A& a6 = constref( A(6) );
std::cout << "a4 = "<< *a4.p <<'\n';
std::cout << "a5 = "<< *a5.p <<'\n';
std::cout << "a6 = "<< *a6.p <<'\n';
}
The output using command line g++-4.8 -std=c++11 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
:
Cstr 4
Cstr 5
Dstr 5
Cstr 6
Dstr 6
a4 = 4
a5 = 0
a6 = 0
Dstr 4
As you can see, the temporary objects referenced by a5
and a6
are destructed at the end of functions thiz
and constref
respectively.
This is an extract of §12.2 Temporary objects, where the bold part applies in this case:
The second context is when a reference is bound to a temporary.
The temporary to which the reference is bound or the temporary
that is the complete object of a subobject to which the reference
is bound persists for the lifetime of the reference except:
- A temporary bound to a reference member in a constructor’s
ctor-initializer (12.6.2) persists until the constructor exits.
- 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.
- 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.
- A temporary bound to a reference in a new-initializer (5.3.4) persists
until the completion of the full-expression containing the new-initializer.
This is a more complete example:
#include <iostream>
struct A
{
A() { std::cout<<"Cstr 9\n"; p = new int(v = 9); }
A(int i) { std::cout<<"Cstr "<<i<<'\n'; p = new int(v = i); }
A(const A&o){ std::cout<<"Copy "<<o.v<<'\n'; p = new int(v = 10+o.v); }
~A() { std::cout<<"Del "<<v<<' '<<*p<<'\n'; *p = 88; delete p; }
const A& thiz() const { return *this; }
int *p;
int v;
};
const A& constref( const A& a )
{
return a;
}
std::ostream& operator<<( std::ostream& os, const A& a )
{
os <<"{ *p="<< *a.p <<" , v="<< a.v <<" }\n";
return os;
}
int main()
{
std::cout << "---const A a1 = A(1)" "\n";
const A a1 = A(1);
std::cout << "---const A a2 = A(2).thiz()" "\n";
const A a2 = A(2).thiz();
std::cout << "---const A a3 = constref( A(3) )" "\n";
const A a3 = constref( A(3) );
std::cout << "---const A& a4 = A(4)" "\n";
const A& a4 = A(4);
std::cout << "---const A& a5 = A(5).thiz()" "\n";
const A& a5 = A(5).thiz();
std::cout << "---const A& a6 = constref( A(6) )" "\n";
const A& a6 = constref( A(6) );
std::cout << "a1 = "<< a1;
std::cout << "a2 = "<< a2;
std::cout << "a3 = "<< a3;
std::cout << "a4 = "<< a4;
std::cout << "a5 = "<< a5;
std::cout << "a6 = "<< a6;
}
And the corresponding output using same g++
command line:
---const A a1 = A(1)
Cstr 1
---const A a2 = A(2).thiz()
Cstr 2
Copy 2
Del 2 2
---const A a3 = constref( A(3) )
Cstr 3
Copy 3
Del 3 3
---const A& a4 = A(4)
Cstr 4
---const A& a5 = A(5).thiz()
Cstr 5
Del 5 5
---const A& a6 = constref( A(6) )
Cstr 6
Del 6 6
a1 = { *p=1 , v=1 }
a2 = { *p=12 , v=12 }
a3 = { *p=13 , v=13 }
a4 = { *p=4 , v=4 }
a5 = { *p=0 , v=5 }
a6 = { *p=0 , v=6 }
Del 4 4
Del 13 13
Del 12 12
Del 1 1