I wrote a scope guard which resets a value when the scope exits:
template <class T>
struct ResetGuard
{
T old_value;
T& obj_to_reset;
ResetGuard(T& obj_to_reset, const T& new_value) :
old_value(obj_to_reset),
obj_to_reset(obj_to_reset)
{
obj_to_reset = new_value;
}
~ResetGuard() { obj_to_reset = old_value; }
};
When this scope guard is returned from a function, is there any way to prevent the immediate destruction of the scope guard if it wasn't saved?
For example:
int GLOBAL_VALUE = 0;
ResetGuard<int> temporarily_set_global_value(int new_val) {
return { GLOBAL_VALUE, new_val }; //updates the global variable
}
void foo() {
//Ideally, someone calling this function
//Wouldn't have to save the returned value to a local variable
temporarily_set_global_value(15);
std::cout << "GLOBAL_VALUE is " << GLOBAL_VALUE << std::endl;
}
The way it's written now, anyone calling one of the functions would have to remember to always save the ResetGuard to a local variable, otherwise it would immediately reset the value.
Some context around what I'm trying to do
I'm writing a library to format and manipulate strings. I have one global variable controlling how floating point numbers are formatted. I know that global variables are typically a terrible idea, but please bear with me.
I made the decision to use a global variable carefully. The alternative to using a global variable would be to pass around the object containing the formatting specification. This option ultimately proved infeasible: my library is designed to work with any objects that provide a implicit conversion to std::string. There's no way to pass formatting options (or any parameters, really) to an implicit conversion function. Hence, I had to resort to using a global variable.
Only one way, assign it to a variable (possibly a reference). If you don't want to burden users of the library, you can hide the details behind a macro. While it's true that the uses of macros become few and far between, this is something you can only do with a macro. For instance, here's how you'd do it with a sprinkle of GCC extensions:
So now when users write:
They get the variable, free of charge, with the expressiveness you wanted.
But of course, there's a caveat. Since we generate the variable name using the pre-processor, we can't use this macro in an inline function. If we do, we'll violate the one definition rule. So that's a thing to consider.
Personally, I wouldn't stress over this. It's a common idiom to require named RAII object (think
lock_guard), so just being presented a properly named function would be straight forward for any savvy C++ programmer.