Nikesh Subedi
Nikesh Subedi

Reputation: 1

Having trouble understanding C++ constructors and destructors and move/copy semantics

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

Answers (1)

JohnFilleau
JohnFilleau

Reputation: 4288

Answer

Nurse 0 DeCreation is shown instead of Nurse 1 DeCreation because:

  1. Nurse has no move assignment operator (see explanation below),
  2. Nurse has a copy assignment operator that is used, and
  3. If Nurse 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 member

Move 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.

Why no move assignment operator?

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.

What if it did have a move assignment operator?

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

Related Questions