Reputation: 41725
myClassVar = MyClass(3);
I expected destructor being called on the previously created myClassVar
on the left.
But it is actually being called on the new object that's created by MyClass(3)
.
My full test code and output follows..
How do I fix the problem?
Implement an assignment operator?
MyClass actually has pointers, and MYSQL_STMT*, I wonder how should I deal with MYSQL_STMT* variable.
I just need MyClassVar(3) object not the MyClassVar() which was first created when ClientClass object was created.
I came across this situation fairly often, and wonder if there's a good way to do it.
#include <stdio.h>
class MyClass
{
public:
MyClass() { printf("MyClass %p\n", this); }
MyClass(int a) { printf("Myclass(int) %p\n", this); }
~MyClass() { printf("~MyClass %p\n", this); }
private:
int mA;
};
class ClientClass
{
public:
void Foo()
{
printf("before &myClassVar : %p\n", &myClassVar);
myClassVar = MyClass(3); // this is the important line
printf("after &myClassVar : %p\n", &myClassVar);
}
private:
MyClass myClassVar;
};
int main()
{
ClientClass c;
c.Foo();
return 0;
}
MyClass 0x7fff5fbfeba0
before &myClassVar : 0x7fff5fbfeba0
Myclass(int) 0x7fff5fbfeb70
~MyClass 0x7fff5fbfeb70 // <--- here destructor is called on the newly created object
after &myClassVar : 0x7fff5fbfeba0
~MyClass 0x7fff5fbfeba0
Upvotes: 5
Views: 1302
Reputation: 153977
Responding to your edit: how do you fix what problem? It's not clear what the problem is. If your class needs a destructor (and there's no polymorphism in play), it probably needs both an assignment operator and a copy constructor. Similarly, when "tracking" construcctions and destructions, you should probably provide both as well, since they will be called.
Otherwise: if the problem is that you're constructing and then assigning, rather than constructing with the correct value immediately, the simple answer is "don't do it". The compiler does what you tell it to. If you write:
MyClass var;
var = MyClass(3);
you have default construction, followed by the construction of a temporary, assignment, and the destruction of the temporary. If you write:
MyClass var(3);
or
MyClass var = 3;
you only have one construction. (Note that despite appearances, there is no assignment in the last snippet. Only construction.)
For class members, this difference appears in the way you write the constructor:
ClientClass::ClientClass() { var = MyClass(3); }
is default construction, followed by creation, assignment and destruction of a temporary;
ClientClass::ClientClass() : var( 3 ) {}
is just construction with the correct value. (Rather obviously, this second form is preferred.)
Upvotes: 1
Reputation: 1721
As the other posts mentioned the object with the custom constructor MyClass(3)
gets destroyed after the assignment operation myClassVar = MyClass(3)
. In this case you do not need a custom assignment operator because the compiler generated one copies the member mA to the already existing object myClassVar.
However since MyClass defines its own destructor you should adhere to the rule of three, which mandates that in such a case you should implement a custom assignment operator as well.
Upvotes: 2
Reputation: 471379
Here's how the critical line breaks down:
myClassVar = MyClass(3);
First, MyClass(3)
calls constructor and returns the object.
Second, myClassVar =
copies the object to myClassVar
.
Then the statement ends. The object (which is an immediate) is dead, and thus the destructor is invoked.
EDIT :
As for how to get around this. The only way I can think of is to use a placement new. I'm not sure if there's a better solution other than making a "set" method.
Upvotes: 6
Reputation: 41351
myClassVar = MyClass(3);
myClassVar
continues to exist after this line. The lifetime of MyClass(3)
ends at the semicolon.
Upvotes: 2