Search code examples
c++this-pointer

Is it safe to reassign *this inside a class' method?


I have an object that is related to some file stored on the disk. The object's constructor accepts this file as an argument, reads it and creates an actual object with the settings depending on the file's content. During the runtime there is a probability for this file to be modified by the user. The object has a method that checks if the file has been modified since the last read, and if this is true, the object has to be updated. There are enough members to be updated inside the object, so instead of manually update each of them it is more convenient to simply create a new object and move it into the existing one(less typing and better readability). But is it actually safe to change *this during the method execution like in the example below?

void Object::update()
{
    if (this->isModified(file)) // Check if a file has been modified since the last read
    {
        try
        {
            Object newObject(file); // May throw
            *this = std::move(newObject); // Is it safe?
        }
        catch (const std::exception& ex)
        {
            // Invalidate and rethrow exception
            this->invalidate();
            throw(ex);
        }
    }
    // ...
}

Solution

  • You seem to be worried about this appearing on the left hand side, though *this = ... merely calls operator=. Typically the assignment operator that takes a rvalue reference just moves the members.

    Consider this simpler example:

    struct foo {
        int x = 42;
        foo& operator=(foo&& other){
            x = std::move(other.x);
            return *this;
        }
        void bar(){
            foo other;
            operator=(std::move(other));
        }
    };
    

    Nothing wrong with that.

    Another way to convince yourself that *this = std::move(newObject); is not problematic is to inline all code from the assignment operator to update. For the example above that would be:

    struct foo {
        int x = 42;
        void bar(){
            foo other;
            x = std::move(other.x);
        }
    };