通过const引用捕获异常并抛出const
Catch exception by const reference and cast away const
如果T
是具有非const
成员函数func
的某个类,那么这个异常处理程序是否有效?
换句话说:catch
是否保证直接绑定到(可修改的)异常对象,或者当您通过const引用捕获时,编译器是否有余地做一些欺骗?
catch(const T &t)
{
const_cast<T &>(t).func();
}
From [exception .throw]:
用操作数计算throw表达式会抛出异常(15.1);异常对象的类型是通过从操作数的静态类型中删除任何顶级cv限定符并调整将"T的数组"或"返回T的函数"转换为"指向T的指针"或"指向返回T的函数的指针",分别。
和,强调我的:
因此,如果抛出一个cv T类型的操作数,则复制初始化了一个T类型的临时对象。抛出异常复制初始化(8.5,12.8)一个临时对象,称为异常对象。的temporary是左值,用于初始化匹配处理程序(15.3)中声明的变量。
然后根据[except]。, const T&(对于非指针类型T)匹配类型E的异常对象,如果:
- […E和T是相同的类型(忽略顶级的cv-限定符),
- […T是E的一个明确的公共基类
这个处理程序初始化:
异常声明声明的类型为cv T或cv T&的变量从异常初始化对象,类型为E,如下:
-如果T是E的基类,则从相应的基类子对象复制初始化(8.5)变量异常对象的;
-否则,从异常对象复制初始化(8.5)。
因此,如果通过const T&捕获,则是对异常对象的引用进行复制初始化——从上一节中我们知道,异常对象要么是T类型的,要么是从T公开派生的。
关键是临时异常对象仍然是左值。因此,如果我们的处理程序匹配const T&,我们知道引用直接绑定到类型T或D的对象(其中D派生自T)—无论哪种方式,它都是与对类型" cv1 T1 "的引用由类型" cv2 T2 "的表达式初始化,如下所示:—如果引用是左值引用,且初始化表达式
是引用兼容的
-是左值(但不是位域),并且" cv1 T1 "与" cv2 T2 "或[…]则引用绑定到第一种情况下的初始化表达式lvalue
const T
引用兼容的类型。因此,不存在未定义的行为。如果临时对象是一个右值,或者处理程序可以匹配更广泛的类型,那么将创建一个const T
类型的临时对象-并且const_cast
肯定是未定义的行为。当你的代码在符合标准的编译器上没有未定义行为时,真的没有理由不这样做:
catch(T &t)
{
t.func();
}
(我使用c++ 11;我需要更新;))
15.1/3(强调我的):
throw表达式初始化一个临时对象,称为异常对象,该对象的类型通过从throw
的操作数的静态类型中删除任何顶级cvs限定符来确定。
这意味着异常对象永远不是"天生的const",因此不应该触发未定义的行为来修改。
我看不出标准中有任何"欺骗"的迹象。无法证明是否定的,但我相信你是"安全的"const
ness在形式上似乎是等价的:
T obj;
const T& t = obj;
const_cast<T &>(t).func();
也就是说,const
属性首先在存在于catch
块中的引用上产生,就是这样。
但这一切都回避了一个问题:如果你不能通过观察来确定,为什么要这样做呢?
一定要抓一个T&
。
正如这里所说:
如果catch子句的参数是引用类型,对它所做的任何更改都将反映在异常对象中,并且如果使用throw重新抛出异常,则可以由另一个处理程序观察到;
因此这表明修改异常对象是安全的,并且更改将是可观察的。
但是,应该考虑通过普通引用来捕获。或者,如果函数只能作用于标记为mutable
的成员,则将其设置为const
。
- 当类定义不可见时捕获异常
- 来自 Android 应用程序内部的 boost 类型的 boost::wrapexcept<boost::system::system_error> 的未捕获异常
- 如何通过 pybind11 从 python 中的C++中捕获异常?
- 信号后未捕获异常
- 捕获异常后如何退出程序执行
- C++ 捕获异常后进行清理的标准方法是什么?
- 使用模板类引发和捕获异常
- E/libc++abi:终止于类型为google::protobuf::FatalException的未捕获异常
- 如果在生成 std::thread 后引发,则未捕获异常
- C++ 未捕获异常,程序将终止并中止
- C++程序在第一次尝试时会给出垃圾,但如果它捕获异常并重试,则会给出适当的值
- 仅捕获异常就可以检测所有二进制文件在C 中读取错误是否足够
- 如何捕获 I/O 异常(确切地说是 I/O,而不是 std::exception)
- 为什么捕获异常播放允许尾括号
- throw() 函数应该总是在异常时展开堆栈并允许捕获异常还是必须调用 std::terminate ?
- 寻求与类型为 std::invalid_argument 的未捕获异常相关的运行时错误的建议: stoi:无转换
- 如何从调用函数中捕获异常
- 当用户在字符数组中输入整数值时捕获异常
- 在c++中捕获const char*异常
- 通过const引用捕获异常并抛出const