C++ ';捕捉';

C++ ';捕捉';,c++,C++,我读了《编程:使用C++的原则和实践》一书(Bjarne Stroustrup)。有时作者写道: catch (runtime_error e) 但有时他写道: catch (runtime_error& e) 正如我所知,第一个变体创建源代码的副本,但第二个变体使用链接。还是我错了?在这种情况下,这对“捕获”不重要吗?您应该始终通过引用捕获;绝对没有理由按价值捕获 不要相信所有写的东西。;-) 我本以为大多数时候,他会使用: catch ( runtime_error const&

我读了《编程:使用C++的原则和实践》一书(Bjarne Stroustrup)。有时作者写道:

catch (runtime_error e)
但有时他写道:

catch (runtime_error& e)

正如我所知,第一个变体创建源代码的副本,但第二个变体使用链接。还是我错了?在这种情况下,这对“捕获”不重要吗?

您应该始终通过引用捕获;绝对没有理由按价值捕获


不要相信所有写的东西。;-)

我本以为大多数时候,他会使用:

catch ( runtime_error const& e )
按值捕获和按引用捕获之间的差异为 与的“按值传递”和“按引用传递”完全相同 函数参数。最重要的区别是 通过引用捕获时,动态类型可以是 派生类型(按值)将导致切片(因为 复印件)

另外,如果通过非常量引用捕获,并修改 异常对象,然后重试,它是
将传播。

为了避免不必要的拷贝和切片,您应该始终通过引用捕获异常。特别是在您计划重新抛出的情况下它。

按值捕获

catch(运行时错误e)

与参考捕获相比

catch(运行时错误&e)

如果您有(通常是多态的)异常类层次结构,并且希望在单个catch子句中捕获所有派生类型的异常,则可以使用后者

例如,标准库中的所有异常类都派生自,因此您可以执行以下操作:

try {
    int i;
    std::cin >> i;
    switch (i) {
        case 1:  throw std::range_error();
        case 2:  throw std::overflow_error();
        case 3:  throw std::undefflow_error();
        default: throw std::logic_error();
    }
} catch (std::exception& e) {
    // handle all the exceptions the same way,
    // but print a diagnostic message polimorphicaly
    std::cout << "I caught: " << e.what() << '\n';
}
试试看{
int i;
标准:cin>>i;
开关(一){
案例1:抛出std::range_error();
案例2:抛出std::overflow_error();
案例3:抛出std::undefflow_error();
默认值:抛出std::logic_error();
}
}捕获(标准::异常&e){
//以相同的方式处理所有异常,
//但是,打印一条诊断信息时,请不要使用任何形式

std::cout,但这是Bjarne Stroustrup写的。他不大可能弄错了。为什么?我不时地按值捕捉。例如,如果你捕捉
int
,我看不出有任何理由使用引用。@JamesKanze:1,抛出
int
有点奇怪,不是吗?2,即使在这种情况下,按引用捕捉也没有什么害处,而反之亦然。(即,按价值捕捉有缺点,按参照捕捉没有缺点;这就是我所说的。)在快速简短的问答页面环境中,我更喜欢给出一些简单的规则,这些规则不能直接打中你的脚,并把休息时间的详细解释留在咖啡室里。-@DevSolar抛出一个
int
是一种干净地退出程序的好方法,只要
main
知道这个惯例。(int
是返回码。)我认为您应该在catch中使用与函数参数相同的约定。@DevSolar:我不会抛出int(因为处理程序中没有指示它的含义);但是抛出一个合理命名的枚举,或者一个包含一个或两个简单类型的结构,对我来说似乎很合理,而且这些东西可能更容易被价值所捕获。简单的指导原则确实很有帮助;像“绝对没有理由”这样的过于简单化第二篇是参考文献。你首先需要了解什么是参考文献,然后阅读我作为副本链接的文章。