Reverting temporary assignment in C++

c++, variable-assignment

Solution

Looks OK to me except that the destructor can throw, which is bad. `swap` with the original value instead of assigning (edit: this deals with `std::string`, but see the comments for possible problems with classes that are less user-friendly than `string`).

If you back off a little from this part of the code, perhaps you can find a way to not need to set a temporary value at all. Shared mutable state in an object can be bad for the same reason that mutable globals are bad, but to a lesser extent because it only messes up your class instead of messing up your whole program.

For example perhaps you could copy the whole object, set a new value for the variable and visit the copy instead of visiting yourself. Obviously that's not necessarily possible or efficient, you have to look for alternatives on a case by case basis. Maybe the copy can be shallow as far as the children are concerned (i.e. refer to the same child objects), that might be sufficient to make it cheap.

Regarding usage, you could deduce the type like this (untested code):

template <typename T, typename ARG>
TemporaryAssignment<T> temp_value(T &var, ARG &&newvalue) {
    return TemporaryAssignment(var, std::forward<ARG>(newValue));
}

Usage:

auto t = temp_value(myVariable, myTemporaryValue);

Then you need a move constructor for TemporaryAssignment:

template <typename TYPE> class TemporaryAssignment {
    // change data member
    TYPE *mVariable;
    TYPE mOriginalValue;
public:
    TemporaryAssignment(TYPE &inVariable, TYPE inValue) 
    : mVariable(&inVariable), mOriginalValue(std::move(inVariable)) {
        *mVariable = std::move(inValue);
    }
    TemporaryAssignment(TemporaryAssignment &&rhs) {
        mOriginalValue = std::move(rhs.mOriginalValue);
        mVariable = rhs.mVariable;
        rhs.mVariable = 0;
    }
    ~TypeAssignment() {
        using std::swap;
        if (mVariable) {
            swap(*mVariable, mOriginalValue);
        }
    }
    // can't remember whether this is needed
    TemporaryAssignment(const TemporaryAssignment &) = delete;
    TemporaryAssignment &operator=(const TemporaryAssignment &) = delete;
    TemporaryAssignment &operator=(TemporaryAssignment &&) = delete;
};

I thought a bit about specifying `operator=` for `TemporaryAssignment` so as to make the usage look like an assignment, but I didn't come up with anything good.

auto t = (temporary(myVariable) = myTemporaryValue);

is plausible, but you probably don't want `TemporaryAssignment` to have `operator=` defined because the meaning of:

t = otherTemporaryValue;

isn't necessarily clear and probably shouldn't be allowed. Maybe with a second class to be returned from `temporary`, and that returns `TemporaryAssignment` from its `operator=`.

Problem

In a visitor context, I need to temporarily set a variable before visiting children, and revert that variable afterward. I'm using the following code, but I'm sure there's a more elegant and proper way to do this: ``` template <typename TYPE> class TemporaryAssignment { protected: TYPE& mVariable; TYPE mOriginalValue; public: TemporaryAssignment(TYPE& inVariable, TYPE inValue) : mVariable(inVariable), mOriginalValue(inVariable) { mVariable = inValue; } ~TemporaryAssignment(void) { mVariable = mOriginalValue; } }; ``` This allows me to write something like the following: ``` { ... TemporaryAssignment<string> t(myVariable, myTemporaryValue); visitChildren(); ... } // previous value of myVariable is restored ``` The variable will revert to its previous value when the temporary assignment object goes out of scope. What is a better way to do this?

Original source