向try块本地抛出一个数组

Ser*_*uin 14 c++ arrays throw c++11

来自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); }

}
Run Code Online (Sandbox Code Playgroud)

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

Jan*_*dec 11

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

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

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

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

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


eer*_*ika 8

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

正确.

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

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

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

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

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

  • @sameerasy,当数据超出范围时,不会释放数据,所以在块结束时.但是发布普通的旧数据并不会用任何东西覆盖它们,只是将内存区域标记为可重用.在你的例子中没有什么可以重复使用它. (4认同)

mar*_*inj 5

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

抛出指针需要指针所指向的对象存在于相应处理程序所在的任何位置.

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

  • 几乎.实际上,由于throw和catch属于同一个函数,如果`a`位于try/catch语句的封闭块中,它也是有效的. (2认同)