L.C.
L.C.

Reputation: 1145

Move semantics: why is the destructor called on the moved instance and is that a problem?

I'm catching up with modern C++, practicing move semantics.

I made a very simple test case:

I noticed that when my instances are destroyed, both destructors are called:

My code deleting a nullptr makes me uncomfortable, here are the questions:

My output for the test (code below) is:

Test 5
        new 0x7512b0
        move_new 0x7512b0
        delete[] 0x7512b0
        delete[] 0

The delete[] 0 output is what grinds my gears.

Here's the main:

#include <iostream>
#include "test5.h"
int main()
{
    std::cout << "Test 5" << std::endl;

    test5 rule5;
    test5 rule5move = std::move(rule5);
    // rule5 = std::move(rule5move);

    return 0;
}

and here's test5.h:

#ifndef TEST5_H
#define TEST5_H

class test5
{
public:
    test5(): data(new float[10]){
        std::cout << "\tnew " << data << std::endl;
        for (int i = 0; i < 10; i++)
            data[i] = float(i);
    }

    ~test5(){
        std::cout << "\tdelete[] " << data << std::endl;
        delete[] data;
    }

    // copy constructor
    test5(const test5& t) : data(new float[10]){
        std::cout << "\tcopy " << data << std::endl;
        std::copy(t.data, t.data + 10, data);
    }

    // copy operator
    test5& operator=(const test5& t){
        std::cout << "\tassign " << data << std::endl;
        std::copy(t.data, t.data + 10, data);
        return *this;
    }

    // move constructor
    test5(test5&& t): data(new float[10]){
        delete[] data;
        data = t.data;
        std::cout << "\tmove_new " << data << std::endl;
        t.data = nullptr;
    }
    // move operator
    test5& operator=(test5&& t){
        delete[] data;
        data = t.data;
        std::cout << "\tmove_assign " << data << std::endl;
        t.data = nullptr;
        return *this;
    }

private:
    float* data;
};

#endif // TEST5_H

Upvotes: 2

Views: 398

Answers (1)

P.W
P.W

Reputation: 26800

is that (deleting nullptr) even a valid operation (i.e. does that result in UB; will it eventually crash my application)?

Deleting nullptr is a no-op. It is valid. As per the online CPP reference:

If expression evaluates to a null pointer value, no destructors are called, and the deallocation function is not called.

I believe your move constructor and move assignment operator are incorrect. Why use raw pointers anyway?

If you are catching up with modern C++ (as you mentioned), you should be using smart pointers.

Upvotes: 2

Related Questions