Destructor Call Missing!

Hi All, I do not really understand what is going on below: Where is the object created in code-location HERE 1? Function stack? Is it a temporary object? It should be as the copy constructor was initiated by the return by-value declaration of f(). At least that is what i think. If it was a temporary why cant I see the destructor called around HERE 2? Where does the reference in HERE 1 point to? Is it the local static or the newly created object?

Can somebody please explain?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include<iostream>
using namespace std;

const double D=1234.12;

class T{
/*A class that writes to cout when ctors or dtors are called*/
public:
	T(double d):d_(d){cout << "Called: T(i)"<<endl;}
	T(const T& t):d_(t.d_){cout << "Called: T(const T&)"<<endl;}
	~T(){d_ = -3333;cout << "Called: ~T()"<<endl;}
	double D(){return d_;};
private:
	double d_;
};

/*Using typedefs to highlight which types are relevant*/
typedef T    RET_VAL_TYPE;
typedef T&   LEFT_HAND_SIDE_TYPE;


/*The function which return type is relevant*/
RET_VAL_TYPE f(){ 
	static T t=T(D);
	return t;
}

int main(){
   /* HERE 0*/ 
f(); //init static, i ignore output that is connected to this statement
cout << "Ignore output before this statement." << endl;
cout << "Now working on statement t = f()." << endl;


  /* HERE 1 */	
LEFT_HAND_SIDE_TYPE t = f(); /*The statement that bothers me.*/

                   cout << "Lets see if the object actually exists: "  
                        << (t.D() ) << " should be equal to " << D << endl;


 /* HERE 2 */ /*Output does not indicate that a destructor is being called around here. Why?*/
}

'
Called: T(i)
Called: T(const T&)
Called: ~T()
Ignore output before this statement.
Now working on statement t = f().
Called: T(const T&)
Lets see if the object actually exists: 1234.12 should be equal to 1234.12
Last edited on
That shouldn't compile, as C++ does not allow binding an rvalue to a non-const reference.
So assuming you meant const T& t = f(); (which requires fixing D() to be const-correct), what's happening is that the reference extends the lifetime of the temporary returned by f() until the end of scope.
So there will be two destructor calls when main() returns, one for t and one for the static object in f().
Didn't know that the lifetime of temporaries can be extended! Thanks Athar! I was expecting to see a reference to void. Also you are right increasing the warning level to 4 VS2010 issues a warning:

warning C4239: nonstandard extension used : 'initializing' : conversion from 'RET_VAL_TYPE'
to 'LEFT_HAND_SIDE_TYPE ... A non-const reference may only be bound to an lvalue


VS2010 talking about initializing and nonstandard extensions I assume this is about initializing the temporary? I don't understand what is nonstandard though. Nevertheless adding an additional scope around the reference and before HERE 2 also creates the call to the destructor that was missing.

In general I don't understand why a non-const reference can only refer to a lvalue. Is it to make sure it exists?
In the example above the value assigned to the non-const reference isnt a lvalue and the reference was non-const. The code went through the compiler only with the warning above not throwing an error and the executable was created. I guess this is not relevant because of the warning the compiler issues?

Still I am struggleing with is: When the compiler anyhow can extends the lifetime of temporarys to keep a reference valid why is it then important that a non-const reference referes to a lvalue and not to a rvalue? To my knowledge the difference between l and r values is only lifetime. Isnt it? As we can address the temporary via the reference makes up for the fact that the reference does not have a name.
Last edited on
Topic archived. No new replies allowed.