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

Nic*_*ick 4 error-handling exception-handling swift

根据文件,

Swift中的错误处理不涉及展开调用堆栈,这个过程计算成本很高

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

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

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

func f() throws {
    let a = A()
    throw MyError.e
}
Run Code Online (Sandbox Code Playgroud)

输出是:

Inited
Deinited
Run Code Online (Sandbox Code Playgroud)

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

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

没有参与

Rob*_*Rob 7

堆栈展开只是导航堆栈中寻找处理程序的过程.维基百科总结如下:

随着搜索的进行,某些语言要求展开堆栈.也就是说,如果函数f包含的处理程序H异常E,调用函数g,后者又调用功能h,和一个异常E发生在h,则功能hg可以被终止,并且Hf将处理E.

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

因此,throw声明的性能特征与声明的性能特征相当return.

所以,使用第一个例子,在Swift f调用g哪个调用h,如果你想f捕获所引发的错误h,那么:

  • h必须明确标明它的throws错误;
  • g必须明确地try呼吁h;
  • g还必须标记它也是throws错误的; 和
  • f必须明确地try调用它g.

简而言之,虽然其他一些语言在查找异常处理程序的过程中提供堆栈展开,但在Swift错误处理中,您必须显式地显示catch您的函数抛出的错误try,或者将其指定为函数,throws以便将失败的try调用返回由呼叫者决定.在Swift中没有自动展开堆栈.

所有这些都与是否发生解除分配无关.正如你所见,是的,throw在Swift中表现得很像return,释放那些局部变量.

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