2

I have written the below piece of code:

#define LOG cout << __PRETTY_FUNCTION__ << endl;

class MyClass
{
private:
    int* ptr;

public:
    MyClass()
        : ptr(new int(10))
    {
        LOG
    }

    ~MyClass()
    {
        LOG

        if (ptr)
        {
            delete ptr;
            ptr = nullptr;
        }
    }

    MyClass(const MyClass& a)
        : ptr(nullptr)
    {
        LOG
        ptr = new int;
        *ptr = *(a.ptr);
    }

    MyClass& operator=(const MyClass& a)
    {
        LOG
        if (this == &a)
        {
            return *this;
        }

        delete ptr;
        ptr = new int;
        *ptr = *(a.ptr);

        return *this;
    }

    MyClass(MyClass&& a)
        : ptr(nullptr)
    {
        LOG

        ptr = a.ptr;
        a.ptr = nullptr;
    }

    MyClass& operator=(MyClass&& a)
    {
        LOG

        if (this == &a)
        {
            return *this;
        }

        delete ptr;
        ptr = a.ptr;
        a.ptr = nullptr;

        return *this;
    }

    void printClass()
    {
        LOG;
    }
};

MyClass function()
{
    MyClass m;
    return m;
}

int main()
{
    MyClass m = function();
    return 0;
}

Output of the program:

MyClass::MyClass()
MyClass::~MyClass()

This does not call the move constructor. Is there something is wrong?

I was expecting the below output:

MyClass::MyClass()
MyClass::MyClass(MyClass&&)
MyClass::~MyClass()
MyClass::MyClass(MyClass&&)
MyClass::~MyClass()
MyClass::~MyClass()

It might look like the compiler is doing some optimisation. If this the case then why we need move constructor or move assignment operator for our case.

Swapnil
  • 1,424
  • 2
  • 19
  • 30
  • Compiler is allowed (and even required) to elide copy and move in certain situations even when the constructors or destructors have side effects. Better post what keywords you searched for. There are lot of answers about that. – Öö Tiib Sep 30 '18 at 12:33
  • *It might look like the compiler is doing some optimisation.* -- I would hope so. If the compiler I was using generated that mess you said you expected to see for a tiny 1 line program, I would throw it away. – PaulMcKenzie Sep 30 '18 at 12:39
  • If you want to see the move constructor actually be invoked, use [std::move explicitly](http://coliru.stacked-crooked.com/a/fad83bc9db81f07d). – PaulMcKenzie Sep 30 '18 at 12:46

1 Answers1

2

This does not call the move constructor. Is there something is wrong?

No, there is nothing wrong.

It might look like the compiler is doing some optimisation.

That's exactly what the compiler did.

If this the case then why we need move constructor or move assignment operator for our case.

Your class needs a custom move constructor and assignment operator, since the implicitly generated ones would not handle the allocated resource correctly.

Just because the compiler might optimise, is not a good reason to leave them out. Especially because in some other program, the move can not be optimized away at all.


PS.

if (ptr) in the destructor is redundant. It's fine to delete nullptr. You don't make the check in operator= either, which is fine.

deleteMe is a dangerous function. Deleting self might be useful in some very obscure cases, but your class doesn't show any need for it. The behaviour of calling this function on a non-dynamic instance would be undefined.

Initialising ptr to null in the move and copy constructor is redundant, since you overwrite the value unconditionally in the body of the constructor.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • `deleteMe` is written to try something out. Not related to this question hence removing it from question to avoid confusion. – Swapnil Sep 30 '18 at 12:39