向try块本地抛出一个数组

时间:2016-01-13 13:26:44

标签: c++ arrays c++11 throw

来自C ++ Primer 18.1.1:

  

如果[thrown]表达式具有数组或函数类型,则表达式为   转换为相应的指针类型。

该程序如何产生9876543210(g ++ 5.2.0)的正确输出?

#include <iostream>
using namespace std;

int main(){

    try{
        int a[10] = {9,8,7,6,5,4,3,2,1,0};
        throw a;
    }
    catch(int* b) { for(int i = 0; i < 10; ++i) cout << *(b+i); }

}

从引号中,throw a将创建一个类型为int*的异常对象,它是指向数组第一个元素的指针。但是当我们退出a块并输入catch子句时,我们肯定会销毁try的数组元素,因为我们改变了块范围?在catch子句的持续时间内,我是否得到了误报,或者数组元素是“单独留下”(未删除)?

3 个答案:

答案 0 :(得分:11)

取消引用悬空指针是Undefined Behavior。

当程序遇到未定义的行为时,可以自由地执行任何。其中包括撞击和使守护进程从你的鼻子中飞出,但它也包括做你想要的任何事情。

在这种情况下,通常不会检查覆盖该部分内存并通过堆栈指针访问的中间操作(在它下面,因为堆栈在大多数平台上增长)。

所以是的,这是误报。内存不能保证不再包含这些值,并且根本不保证可以访问,但它仍然包含它们并且可以访问。

另请注意,gcc优化对于依赖于不调用未定义行为的程序而言相当臭名昭着。通常,如果您有未定义的行为,未经优化的版本似乎可以正常工作,但是一旦启用优化,它就会开始做一些完全出乎意料的事情。

答案 1 :(得分:8)

  

但是当我们退出try块并且因为我们改变块范围而输入catch子句时,a的数组元素肯定会被销毁吗?

正确。

  

在catch子句的持续时间内,我是否得到了误报或数组元素“单独”(未删除)?

他们不是“孤身一人”。正确假设时会破坏阵列。该程序正在访问无效内存。行为未定义。

  

该程序如何产生9876543210(g ++ 5.2.0)的正确输出?

未定义行为时,没有正确的输出。程序可以产生它所做的事情,因为它可以在行为未定义时产生任何输出。

关于UB的推理通常是没有意义的,但在这种情况下,如果程序中尚未覆盖部分内存,则无效内存的内容可能相同。

答案 2 :(得分:5)

您将在本章后面找到警告:

  

抛出指针需要指针指向的对象   在相应的处理程序所在的任何地方都存在点。

所以如果a数组是静态的或全局的,那么你的例子将是有效的,否则它的UB。或者(正如Jan Hudec在评论中写的那样)在try / catch语句的封闭块中。

相关问题