Swift中的错误处理不涉及堆栈展开。这是什么意思?

时间:2017-10-18 15:46:12

标签: swift error-handling exception-handling

根据文件,

  Swift中的

错误处理不涉及展开调用堆栈,a   过程可能是计算上昂贵的

我想知道它是什么意思?我一直认为堆栈展开是一个在异常情况下(就C ++而言)正确调用析构函数的过程。

所以我决定对情况进行建模:

class A {
    init() {
        print("Inited")
    }
    deinit {
        print("Deinited")
    }
}

func f() throws {
    let a = A()
    throw MyError.e
}

输出结果为:

Inited
Deinited

所以"析构函数"被称为 - 这意味着(在我的理解中)堆栈展开在Swift中起作用。

任何人都可以解释为什么文档说它是

  

没有参与

2 个答案:

答案 0 :(得分:7)

堆栈展开只是在堆栈中导航寻找处理程序的过程。维基百科summarizes it as follows

  

在此搜索过程中,某些语言要求展开堆栈。也就是说,如果函数f包含异常H的处理程序E,则调用函数g,而函数h又调用函数E和异常{ {1}}中出现{1}},然后hh可能会被终止,g中的H会处理f。< / p>

而Swift错误不会解除堆栈查找处理程序的问题。它只是返回,并期望调用者处理抛出的错误。事实上,你引用goes on to say之后的句子:

  

因此,E语句的性能特征与throw语句的性能特征相当。

因此,使用第一个示例,其中return调用f调用g,在Swift中,如果您希望h捕获{{1}引发的错误然后:

  • f必须明确标记为h错误;
  • h必须明确throws调用g;
  • try也必须标记为h错误;和
  • g必须明确throws调用f

简而言之,虽然其他一些语言在查找异常处理程序的过程中提供了堆栈展开,但在Swift错误处理中,您必须明确try函数g抛出的错误,或者是指定为catch的函数,以便将失败的try调用返回给调用者。在Swift中没有自动展开堆栈。

所有这些都与是否发生解除分配无关。正如您所见,是的,Swift中的throwstry的行为非常相似,会释放这些局部变量。

值得注意的是,并非所有涉及堆栈展开的异常处理都会进行重新分配。通常它确实如此(因为当我们处理异常时我们希望它清理),但是例如,“当发生未处理的异常时,GNU C ++ unwinder不会调用对象析构函数。原因是为了提高可调试性。 “ (来自Exception Handling in LLVM。)显然,这仅适用于调试环境中未处理的异常,但它说明了展开堆栈并不一定意味着对象被释放的问题。

答案 1 :(得分:0)

如果swift堆栈展开,那么它将调用自块开始以来分配的所有对象的所有析构函数。但反过来可能并非如此。仅仅因为为你的对象A调用析构函数,意味着快速堆栈展开。此外,如果你真的想测试它是否是堆栈展开,你应该尝试一个更严格的例子