1

It might be a stupid question but I feel like I am missing some design pattern.

During the destruction of a class I would like to do different operations if it was moved or not. I thought about implementing a simple boolean that is ticked when the class is moved.

Like this:

class A {
    A(A && a) {
        a.was_moved = true;
    }

~A() {
    do some stuff

    if (!was_moved) {
        clean some more stuff
    }

bool was_moved = false;
};

Is there a "better" way doing this? some cpp feature I could ask if the class was moved or some known design pattern.

MSalters
  • 173,980
  • 10
  • 155
  • 350
Epic
  • 572
  • 2
  • 18

2 Answers2

3

There is no feature that allows that. But generally you don't need to know that.

Normally when you define a move constructor you want it to "move" the underlying data from one object to another. In your context it seems that you want the source object to be "empty" afterwards so that there is only one owner (after all it is "move", not "copy"). So what you really need is a proper definition of an "empty" object and a proper way of handling that case.

For example, assume that your class is associated with a file descriptor. Then you can have a default value of fd equal to -1 and differentiate destructor on that:

#include <utility>

class A
{
    public:
        A(int fd) : fd { fd }
        {
        }

        A(A&& other) : fd { std::exchange(other.fd, -1) }
        {
        }

        ~A()
        {
            if (fd != -1)
            {
                close(fd);
            }
        }

    private:
        int fd = -1;
};

Of course you can mark the object as empty via additional flag. And indeed people do this in some special cases. Even in the standard library. You may want to read this. Note the __owns_ flag on the unique_lock class.

freakish
  • 54,167
  • 9
  • 132
  • 169
2

There is no standard way of knowing it. But it is important to define both Move Constructor and Move assignment so that you can clean up the exisitng object's resource before move is performed:

class MoveDemo
{
    size_t size;
    char *buf;

    public:
    explicit MoveDemo(int sz=1024):size(sz), buf(new char[size]) {}
    ~MoveDemo { delete [] buf; }
    MoveDemo(MoveDemo&& other);
    MoveDemo& operator=(MoveDemo&& other);
};

MoveDemo::MoveDemo(MoveDemo&& other):size(0), buf(nullptr)
{
    size = other.size;
    buf = other.buf;

    //reset other
    other.size = 0;
    other.buf = nullptr;
}

MoveDemo& MoveDemo::operator=(MoveDemo&& other)
{
    if (this != &other)
    {
        // release current objects resources
        delete [] buf;
        size = 0;

        // move
        size = other.size;
        buf = other.buf;

        //reset other
        other.size = 0;
        other.buf = nullptr;
    }
    return *this;
}
Archie Yalakki
  • 512
  • 4
  • 12