赋值的计算顺序,对于一个基本类型的变量,右操作数抛出异常
Computation sequence of assignment, for a variable of fundamental type, with right operand throwing an exception
如果我使用可能抛出的表达式为基本类型的变量赋值,是否保证抛出异常时变量的状态不变?
例如,在下面的代码中,如果我们选择 'Option A' 并且 operator new()
抛出异常,那么成员是否有 any 机会当在堆栈展开期间调用析构函数时,变量 ptr
将不等于 nullptr
?
#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);
}
};
我很想知道 C++14 和 C++17 的答案。
我的猜测:'Option A' 在 C++14 和 C++17 中是安全的,因为它们都包含此语句(参见 § [expr.ass] ¶ 1):
In all cases, the assignment is sequenced after the value computation of the right and left operands
但是,我不确定执行左操作数的 'value computation' 是否不包括为其赋予新值。我没有在标准中找到 'value computation' 的定义。
相关(但我不清楚):
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?
我会暂时忘记 ptr
在 new
调用之前实际上从未在 MemoryHolder
中初始化,因此可能具有不确定的值。因此,您的问题是 "will ptr
have the same value before the assignment as it does after?"
就您可以实际验证这一点的程度而言(在构造函数中,意味着您必须实际捕获构造函数内部的异常),是的,它将具有相同的值。
I did not find a definition of 'value computation' in the standard.
虽然该标准有时会深入研究古怪的语言,但它并不是要主动欺骗您。如果一个术语没有定义,那么它应该按字面意思来理解。 "Value computation" 表示...计算值。您正在将 A 分配给 B。这意味着弄清楚 A 和 B 是什么。其中涉及为它们计算值,然后执行赋值。
Related (but unclear to me): Assignment in C++ occurs despite exception on the right side
这与您的问题无关,因为那是关于作业双方 "value computation" 的顺序,而不是关于 执行 作业。那个问题的OP弄错了。分配从未真正发生过。只是 map::operator[]
将在地图中创建一个条目(如果条目尚不存在)。由于 C++14 没有对赋值操作的两侧进行排序,因此实现可以允许它们以任何顺序发生。在这种情况下,operator[]
先发生,因此即使没有发生赋值也插入了一个元素。
如果我使用可能抛出的表达式为基本类型的变量赋值,是否保证抛出异常时变量的状态不变?
例如,在下面的代码中,如果我们选择 'Option A' 并且 operator new()
抛出异常,那么成员是否有 any 机会当在堆栈展开期间调用析构函数时,变量 ptr
将不等于 nullptr
?
#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);
}
};
我很想知道 C++14 和 C++17 的答案。
我的猜测:'Option A' 在 C++14 和 C++17 中是安全的,因为它们都包含此语句(参见 § [expr.ass] ¶ 1):
In all cases, the assignment is sequenced after the value computation of the right and left operands
但是,我不确定执行左操作数的 'value computation' 是否不包括为其赋予新值。我没有在标准中找到 'value computation' 的定义。
相关(但我不清楚):
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?
我会暂时忘记 ptr
在 new
调用之前实际上从未在 MemoryHolder
中初始化,因此可能具有不确定的值。因此,您的问题是 "will ptr
have the same value before the assignment as it does after?"
就您可以实际验证这一点的程度而言(在构造函数中,意味着您必须实际捕获构造函数内部的异常),是的,它将具有相同的值。
I did not find a definition of 'value computation' in the standard.
虽然该标准有时会深入研究古怪的语言,但它并不是要主动欺骗您。如果一个术语没有定义,那么它应该按字面意思来理解。 "Value computation" 表示...计算值。您正在将 A 分配给 B。这意味着弄清楚 A 和 B 是什么。其中涉及为它们计算值,然后执行赋值。
Related (but unclear to me): Assignment in C++ occurs despite exception on the right side
这与您的问题无关,因为那是关于作业双方 "value computation" 的顺序,而不是关于 执行 作业。那个问题的OP弄错了。分配从未真正发生过。只是 map::operator[]
将在地图中创建一个条目(如果条目尚不存在)。由于 C++14 没有对赋值操作的两侧进行排序,因此实现可以允许它们以任何顺序发生。在这种情况下,operator[]
先发生,因此即使没有发生赋值也插入了一个元素。