Reputation: 21
In the code below, the destructor of class B
is called in Case 1 but not in Case 2, when the execution returns back to main
from fn()
. I don't understand this difference, since both are on heap memory when A
is created with new
. Could you please explain?
class B {
public:
B() {
printf(" [B] COntsructor");
}
~B() {
printf(" [B] Destructor");
}
};
class A {
public:
A() {
printf(" [A] COntsructor");
}
~A() {
printf(" [A] Destructor");
}
B Query() { return b; } /// Case 1
B* Query() { return &b; } /// Case 2
B b;
};
void fn()
{
A *a = new A();
B b = a->Query(); // case 1
B* b = a->Query(); // case 2
return;
}
int _tmain(int argc, _TCHAR* argv[])
{
fn();
return 0;
}
Upvotes: 1
Views: 523
Reputation: 31952
Case 1: When you return b
by value the local variable b
is constructed using the copy constructor. All but one copy is optimized away by Return Value Optimization. The destruction of the local variable b
triggers the destructor.
Case 2: When you return &b
all you are returning is a pointer to b
and so there is no destruction necessary.
Edit: The code shows the destructor being called without a corresponding call to the constructor. This is because the function return copy is happening through the copy constructor.
Edit2: @ZarShardan is correct - the "Many copies" I refered to would likely not exist thanks to Return Value Optimization.
Upvotes: 3
Reputation: 5931
Object a is never deleted, so neither its own destructor nor its member object(s) destructor(s) is(are) called.
Try adding
delete a;
in the end of your function fn()
or better use std::unique_ptr instead of a bare pointer. That's better design in case your Query member function throws an exception (RAII stuff)
Upvotes: -1
Reputation: 60858
a
will never get deleted, so no destructors for it or its members.a->b
will be constructed using the default constructor, so that's the constructor call you see.B b = a->Query();
will be created using the copy constructor, which doesn't print anything.fn
, the local b
will go out of scope, so that's your destructor call.Things might become clearer if you add debug code for the copy constructor, if you have all debug code print the value of this
, and if you eventually delete a
to see those destructor calls as well.
Upvotes: 1
Reputation: 34895
I don't see you creating a new
instance of B
in the second case, thus the pointer that A holds as a member would be cleaned up with A
's destructor and since a constructor in B
was never invoked a destructor won't be invoked either.
Upvotes: 0