If I use an expression that may throw to assign a value to a variable of fundamental type, is it guaranteed that the state of the variable is unaltered if an exception is thrown?
For instance, in the following code, if we choose 'Option A' and an exception is thrown by operator new()
, is there any chance that the member variable ptr
will not be equal to nullptr
when the destructor will be called during the stack unwinding?
#include <new> // operator new operator delete
class MemoryHolder {
private:
void * ptr;
public:
MemoryHolder () {
ptr = nullptr;
}
void increase_memory () {
operator delete (ptr);
ptr = nullptr;
// Option A (unsafe?)
ptr = operator new (10);
// Option B (safe)
void * new_ptr = operator new (10);
ptr = new_ptr;
}
~MemoryHolder () {
operator delete (ptr);
}
};
I am interested to know the answer for both C++14 and C++17.
My guess: 'Option A' is safe in C++14 and C++17 because they both contain this statement (cf. § [expr.ass] ¶ 1):
In all cases, the assignment is sequenced after the value computation of the right and left operands
However, I am not sure that performing the 'value computation' of the left operand doesn't include giving it its new value. I did not find a definition of 'value computation' in the standard.
Related (but unclear to me): Assignment in C++ occurs despite exception on the right side
in the following code, if we choose 'Option A' and an exception is thrown by
operator new()
, is there any chance that the member variableptr
will not be equal tonullptr
when the destructor will be called during the stack unwinding?
I will forget for a moment that ptr
is never actually initialized in MemoryHolder
before the new
call and therefore may have an indeterminate value. Thus, your question is "will ptr
have the same value before the assignment as it does after?"
To the degree that you can actually verify this (which in the constructor, means you'd have to actually catch the exception inside of the constructor), yes, it will have the same value.
I did not find a definition of 'value computation' in the standard.
While the standard sometimes delves into oddball language, it is not trying to actively deceive you. If a term is not defined, then it should be taken at face value. "Value computation" means... computing the value. You're assigning A to B. That means figuring out what both A and B are. Which involves computing values for them, then performing assignment.
Related (but unclear to me): Assignment in C++ occurs despite exception on the right side
That's unrelated to your question, because that's about the order of the "value computation" for both sides of the assignment, not about performing the assignment. The OP of that question got it wrong. The assignment never actually happens. It's just that map::operator[]
will create an entry into the map if one does not already exist. And since C++14 does not sequence the two sides of the assignment operation, implementations can allow them to happen in any order. And in that case, operator[]
happened first, thus an element was inserted even though no assignment happened.