Reputation: 1
I have the following program where I test the order of constructor and destructor calls and I was surprised by the output.
#include <iostream>
#include <utility>
class Doctor {
public:
Doctor(){
std::cout << "Doctor Creation\n";
}
~Doctor(){
std::cout << "Doctor DeCreation\n";
}
};
class Nurse{
public:
int op = 0;
Nurse(){
std::cout << "Nurse Creation\n";
}
~Nurse(){
std::cout << "Nurse " << op << " DeCreation\n";
}
};
class Hospital{
private:
Doctor doc;
Nurse nurse;
public:
Hospital(){
std::cout << "Hospital Creation\n";
}
~Hospital(){
std::cout << "Hospital DeCreation\n";
}
void operate(){
std::cout << "Hospital Operation\n";
nurse.op++;
std::cout << &this->nurse << " " << nurse.op << "\n";
reset_hospital();
std::cout << &this->nurse << " " << nurse.op << "\n";
}
void reset_hospital(){
std::cout << &this->nurse << " " << nurse.op << "\n";
nurse = std::move(Nurse());
doc = std::move(Doctor());
}
};
int main(){
Hospital hospital;
hospital.operate();
}
https://godbolt.org/z/bf8KbqsTK
The output is:
Doctor Creation
Nurse Creation
Hospital Creation
Hospital Operation
0x7fff2316866c 1
0x7fff2316866c 1
Nurse Creation
Nurse 0 DeCreation
Doctor Creation
Doctor DeCreation
0x7fff2316866c 0
Hospital DeCreation
Nurse 0 DeCreation
Doctor DeCreation
Shouldn't it be Nurse 1 DeCreation
on the std::move operation? The current object is destroyed and replaced by the new one? Or for some reason, is it copying instead of moving?
I'm so confused.
Upvotes: 0
Views: 63
Reputation: 4288
Nurse 0 DeCreation
is shown instead of Nurse 1 DeCreation
because:
Nurse
has no move assignment operator (see explanation below),Nurse
has a copy assignment operator that is used, andNurse
had an implicitly-defined move assignment operator, it would be trivial, and the members would be acted on as if by std::memmove
, which would not swap the underlying op
memberMove semantics do not guarantee that a swap will occur. In the case of trivially movable member variables, assignment is much more efficient than swapping. Move semantics don't necessarily guarantee that the "moved-from" object will be the same as the previous state of the "moved-to" object. Move semantics only (should) guarantee that the moved-from object is in a valid state. It can be unspecified.
https://en.cppreference.com/w/cpp/language/move_assignment
If no user-defined move assignment operators are provided for a class type (struct, class, or union), and all of the following is true:
- there are no user-declared copy constructors;
- there are no user-declared move constructors;
- there are no user-declared copy assignment operators;
- there is no user-declared destructor,
then the compiler will declare a move assignment operator as an inline public member of its class with the signature T& T::operator=(T&&).
Nurse
has a user-declared destructor, and therefore has no implicitly declared move assignment operator
Nurse
does have an implicitly defined copy assignment operator, and its members are copied. The first-destroyed Nurse
object has op = 0
, so you see Nurse 0 DecCreation
.
If ~Nurse()
was not user provided, then Nurse
would have an implicitly declared move assignment operator. It would also be a trivial move assignment operator, which only guarantees the members are assigned as if using std::memmove
. I.e., byte-wise copied.
Upvotes: 1