C++ 为什么在C++;?
我目前正在处理异常类型,在尝试重新抛出捕获的异常时,我注意到了一些奇怪的事情。C++ 为什么在C++;?,c++,exception,inheritance,C++,Exception,Inheritance,我目前正在处理异常类型,在尝试重新抛出捕获的异常时,我注意到了一些奇怪的事情。 从C++规范中,我知道抛出实际上会产生一个你试图抛出的对象的拷贝,所以你最终会将你捕获的任何派生的类型信息切片。 为了避免这种情况,我看到了重新抛出指向原始异常的指针的建议,因为实际的原始对象将不会删除其派生部分。 然而,我在下面编写的简单示例程序似乎不能以这种方式工作: #包括 #包括 #包括 类派生的_异常:public std::exception{}; 无效重试例外(bool匿名){ 试一试{ 抛出派生的_异
从C++规范中,我知道
#包括
#包括
#包括
类派生的_异常:public std::exception{};
无效重试例外(bool匿名){
试一试{
抛出派生的_异常();
}捕获(const std::exception&e){
std::cout 1.抛出什么?
5.17引发异常
没有操作数的抛出表达式将重新抛出当前处理的异常
15.1引发异常
抛出异常副本会初始化一个临时对象,称为异常对象。临时对象是一个左值,用于初始化匹配处理程序中声明的变量
对于语句throw;
,它将重新抛出当前异常对象派生的\u exception()
对于语句throw&e;
,它将创建一个类型为std::exception*
的临时对象,实际上相当于throw(std::exception*,除了_obj=&e);
2.哪个catch
catch?
15.1引发异常
抛出异常副本会初始化一个临时对象,称为异常对象。临时对象是一个左值,用于初始化匹配处理程序中声明的变量。
15.3处理异常
处理程序与类型为E的异常对象匹配,如果
- [3.1]处理程序的类型为cv T或cv T&且E和T的类型相同(忽略顶级cv限定符),或
- [3.2]处理程序的类型为cv T或cv T&且T是明确的公共基类E,或
- [3.3]处理程序的类型为cv T或const T&其中T为指针类型,E为指针类型,可通过以下任一种或两种方式转换为T:
- 一种标准指针转换(4.10),不涉及到私有类、受保护类或不明确类指针的转换
- 资格转换,或
- [3.4]处理程序的类型为cv T或const T&其中T是一个指针或指向成员类型的指针,E是std::nullptr\T
try块的处理程序按外观顺序进行尝试
当匿名==true
:
执行throw;
,从而重新抛出异常对象派生的\u exception()
,然后从以下各项中选择一个入口点:
捕获(常量派生的\u异常&e)
- 和
catch(const std::exception&e)
从标准15.3-3-3.2中,我们知道derived_exception()
匹配catch(const-derived_exception&e)
。因此,输出为:
Re-caught: 17derived_exception (std::exception)
当匿名==false时
:
执行throw&e;
,从而创建一个类型为std::exception*
的临时异常对象,然后从以下对象中选择一个入口点:
catch(常量派生的\u异常*e)
- 和
catch(const std::exception*e)
我们不能选择前者。因为标准15.3-3中的四条规则中没有一条规定std::exception*
与const-derived\u exception*
相匹配
因此,选择后面的catch
。我们可以看到输出:
Re-caught: PKSt9exception (std::exception)
(您可能想讨论第三条规则[3.3],但标准指针转换和限定转换都不支持从基类指针到子类指针的转换,必须明确地执行向下转换,就像使用动态_cast()
)
3.在你的问题中
从C++规范中,我知道抛出实际上会产生一个你要抛出的对象的拷贝,
对
因此,您将对捕获到的任何剩余派生类型信息进行切片
如果在catch
中使用值类型而不是引用或指针,则正确
try {
throw derived_exception();
} catch (const std::exception e) {
...
}
从标准15.1-3中,我们知道这里e
将用derived_exception()
初始化。实际上,这就像执行e=derived_exception();
。不过,我找不到任何使用此表单的理由
我看到过一些建议,建议重新抛出指向原始异常的指针,因为实际的原始对象将不会删除其派生部分
通过将typeid(e).name()
替换为typeid(*e).name()
,我们可以看到原始对象未被切片:
catch (const std::exception *e)
{
std::cout << "Re-caught: " << typeid(*e).name() << " (std::exception)"
<< std::endl;
}
// Re-caught: 17derived_exception (std::exception)
catch(const std::exception*e)
{
std::coutderived_exception
是从exception
派生而来的,但是derived_exception*
不是从exception*
派生而来的。因此,不要通过指针捕捉异常,而是通过常量引用捕捉异常。匿名化
是一个错误的名称,因为true
时,您得到了正确的类型,使用false,你有基本类型……抛出/捕获系统不会为你编写代码>动态DistaCase指针。“从C++规范中,我知道投掷实际上会产生一个你试图抛出的对象的拷贝,所以你最终将删除你捕获的任何残余派生类型信息。”-我不认为这是真的。
catch (const std::exception *e)
{
std::cout << "Re-caught: " << typeid(*e).name() << " (std::exception)"
<< std::endl;
}
// Re-caught: 17derived_exception (std::exception)