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?
Looks OK to me except that the destructor can throw, which is bad.
swapwith the original value instead of assigning (edit: this deals withstd::string, but see the comments for possible problems with classes that are less user-friendly thanstring).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):
Usage:
Then you need a move constructor for TemporaryAssignment:
I thought a bit about specifying
operator=forTemporaryAssignmentso as to make the usage look like an assignment, but I didn’t come up with anything good.is plausible, but you probably don’t want
TemporaryAssignmentto haveoperator=defined because the meaning of:isn’t necessarily clear and probably shouldn’t be allowed. Maybe with a second class to be returned from
temporary, and that returnsTemporaryAssignmentfrom itsoperator=.