【发布时间】:2022-01-23 21:47:23
【问题描述】:
我很想知道将异常对象移动到某个局部变量是否正确。这个动作有没有可能导致UB?我的担心是由于引用捕获假定访问位于其他地方的异常对象(因为它必须一直存在到堆栈展开结束)。请参见下面的示例。
int main()
{
std::pair<int,int> res; //may be heavy object, it's only example
int a[3][5];// assume filled
try
{
for(int i = 0; i < 3; ++i)
{
for(int j = 0; j < 5; ++j)
{
if(a[i][j] % 2 ==0 )
{
throw std::pair<int,int>(i,j);
}
}
}
}catch(std::pair<int,int>& pair)
{
res = std::move(pair);
}
}
【问题讨论】:
-
a
pair<int,int>仍然会被复制。 -
异常不应是“重”对象。
-
移动一个异常对象很好:结果无论如何都需要是可破坏的,并且在大多数情况下你不会关心对象的状态。当然,如果您打算重新抛出异常,它会将其状态更改为某个不确定的状态(尽管在
std::pair<int, int>移动对象的情况下不会影响原始对象 - 它将始终被复制)。 -
虽然我看不出有什么优势,但我认为不会有问题。一点旁注:不应在正常执行流程中抛出异常,而应仅针对罕见的异常事件。
-
自 C++11 起,捕获异常对象并将其寿命延长到
catch块之外的标准方法是使用std::current_exception(),但我看不到任何访问它捕获的对象,您只能使用std::rethrow_exception()重新抛出它。