87 lines
17 KiB
HTML
87 lines
17 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="zh" dir="ltr" class="client-nojs" xmlns="http://www.w3.org/1999/xhtml" xml:lang="zh">
|
|
<head><meta http-equiv="x-ua-compatible" content="ie=edge">
|
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
|
<title>异常</title>
|
|
<link rel="stylesheet" href="ext.css" />
|
|
<link rel="stylesheet" href="site_modules.css" />
|
|
</head>
|
|
<body class="mediawiki ltr sitedir-ltr ns-0 ns-subject page-cpp_language_exceptions skin-cppreference2 action-view cpp-navbar">
|
|
<div id="cpp-content-base">
|
|
<div id="content"><a id="top"></a>
|
|
<h1 id="firstHeading" class="firstHeading">异常</h1>
|
|
<div id="bodyContent">
|
|
<div id="contentSub"><span class="subpages">< <a href="cpp.html">cpp</a>‎ | <a href="cpp-language.html">language</a></span></div>
|
|
<div id="mw-content-text" lang="zh" dir="ltr" class="mw-content-ltr" xml:lang="zh">
|
|
<p>异常处理提供了一种可以使程序从执行的某点将控制流和信息转移到与执行先前经过的某点相关联的处理代码的方法(换言之,异常处理将控制权沿调用栈向上转移)。</p>
|
|
<p><a href="cpp-language-throw.html">throw 表达式</a>、<a href="cpp-language-dynamic_cast.html">dynamic_cast</a>、<a href="cpp-language-typeid.html">typeid</a>、<a href="cpp-language-new.html">new 表达式</a>、<a href="cpp-memory-new-operator_new.html">分配函数</a>,以及专门用来抛出特定异常以指示特定错误状态的任何标准库函数(例如 <span class="t-lc"><a href="cpp-container-vector-at.html">std::vector::at</a></span>、<span class="t-lc"><a href="cpp-string-basic_string-substr.html">std::string::substr</a></span> 等)都可以抛出异常。</p>
|
|
<p>为捕获异常,throw 表达式必须在 <a href="cpp-language-try_catch.html">try 块</a>或者 try 块中所调用的函数中,而且必须有与异常对象的类型相匹配的 <a href="cpp-language-try_catch.html">catch 子句</a>。</p>
|
|
<p>在声明函数时,可以提供以下说明以限制函数能够抛出的异常类型:</p>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-until-cxx17">
|
|
<td>
|
|
<ul>
|
|
<li><a href="cpp-language-except_spec.html">动态异常说明</a></li>
|
|
</ul>
|
|
</td>
|
|
<td><span class="t-mark-rev t-until-cxx17">(C++17 前)</span></td>
|
|
</tr>
|
|
</table>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx11">
|
|
<td>
|
|
<ul>
|
|
<li><a href="cpp-language-noexcept_spec.html">noexcept 说明</a></li>
|
|
</ul>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<p>异常处理过程中发生的错误由 <span class="t-lc"><a href="cpp-error-terminate.html">std::terminate</a></span> <span class="t-rev-inl t-until-cxx17"><span>和 <span class="t-lc"><a href="cpp-error-unexpected.html">std::unexpected</a></span></span> <span><span class="t-mark-rev t-until-cxx17">(C++17 前)</span></span></span> 处理。</p>
|
|
<h3><span class="mw-headline" id=".E7.94.A8.E6.B3.95">用法</span></h3>
|
|
<p>尽管 throw 表达式转移控制到执行栈上方的任意代码块时没有条件限制(类似 <span class="t-lc"><a href="cpp-utility-program-longjmp.html">std::longjmp</a></span>),但它的预期用途还是进行错误处理。</p>
|
|
<h4><span class="mw-headline" id=".E9.94.99.E8.AF.AF.E5.A4.84.E7.90.86">错误处理</span></h4>
|
|
<p>异常的抛出用于从函数中为错误发信号,其中“错误”通常仅限于以下内容<sup id="cite_ref-1" class="reference"><a href="cpp-language-exceptions.html#cite_note-1">[1]</a></sup><sup id="cite_ref-2" class="reference"><a href="cpp-language-exceptions.html#cite_note-2">[2]</a></sup><sup id="cite_ref-3" class="reference"><a href="cpp-language-exceptions.html#cite_note-3">[3]</a></sup>:</p>
|
|
<ol>
|
|
<li>无法满足后置条件,例如不能产生有效的返回值对象</li>
|
|
<li>无法满足另一个必须调用的函数的前置条件</li>
|
|
<li>(对于非私有成员函数)无法(再)建立类不变量</li>
|
|
</ol>
|
|
<p>这意味着构造函数(参阅 <a href="cpp-language-raii.html">RAII</a>)和大多数运算符应该通过抛出异常来报告程序错误。</p>
|
|
<p>另外,所谓<i>宽契约(wide contract)</i>函数用异常来指示非法输入,例如,<span class="t-lc"><a href="cpp-string-basic_string-at.html">std::string::at</a></span> 没有前置条件,但它会抛出异常以指示下标越界。</p>
|
|
<h4><span class="mw-headline" id=".E5.BC.82.E5.B8.B8.E5.AE.89.E5.85.A8">异常安全</span></h4>
|
|
<p>在函数报告了错误状态后,可以提供附加保证以保障程序的状态。以下是四个被广泛认可的异常保证等级<sup id="cite_ref-4" class="reference"><a href="cpp-language-exceptions.html#cite_note-4">[4]</a></sup><sup id="cite_ref-5" class="reference"><a href="cpp-language-exceptions.html#cite_note-5">[5]</a></sup><sup id="cite_ref-6" class="reference"><a href="cpp-language-exceptions.html#cite_note-6">[6]</a></sup>,每个是另一个的严格超集:</p>
|
|
<ol>
|
|
<li><i>不抛出(nothrow)(或不失败)异常保证</i>——函数始终不会抛出异常。<a href="cpp-language-destructor.html">析构函数</a>和其他可能在栈回溯中调用的函数被期待为不会抛出(以其他方式报告或隐瞒错误)。<span class="t-rev-inl t-since-cxx11"><span><a href="cpp-language-destructor.html">析构函数</a>默认为 <a href="cpp-language-noexcept.html">noexcept</a>。</span> <span><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></span></span>交换函数(swap),<a href="cpp-language-move_constructor.html">移动构造函数</a>,及为提供强异常保证所使用的其他函数,都被期待为不会失败(函数总是成功)。</li>
|
|
<li><i>强(strong)异常保证</i>——如果函数抛出异常,那么程序的状态会恰好被回滚到该函数调用前的状态。(例如 <span class="t-lc"><a href="cpp-container-vector-push_back.html">std::vector::push_back</a></span>)</li>
|
|
<li><i>基础(basic)异常保证</i>——如果函数抛出异常,那么程序处于某个有效状态。不泄漏资源,而所有对象的不变式都保持完好。</li>
|
|
<li><i>无异常保证</i>——如果函数抛出异常,那么程序可能不会处于有效的状态:可能已经发生了资源泄漏、内存损坏,或其他摧毁不变式的错误。</li>
|
|
</ol>
|
|
<p>此外,泛型组件还可以提供<i>异常中性(exception neutral)保证</i>:如果从某个模板形参(例如从 <span class="t-lc"><a href="cpp-algorithm-sort.html">std::sort</a></span> 的 <code>Compare</code> 函数对象,或从 <span class="t-lc"><a href="cpp-memory-shared_ptr-make_shared.html">std::make_shared</a></span> 中 <code>T</code> 的构造函数)抛出异常,那么它会被无修改地传播给调用方。</p>
|
|
<h3><span class="mw-headline" id=".E5.BC.82.E5.B8.B8.E5.AF.B9.E8.B1.A1">异常对象</span></h3>
|
|
<p>虽然任意完整类型和指向 void 的 cv 指针都能作为异常对象抛出,但所有标准库函数都以值抛出匿名临时对象,而且这些对象的类型都(直接或间接)派生于 <span class="t-lc"><a href="cpp-error-exception.html">std::exception</a></span>。用户定义的异常通常遵循此模式。<sup id="cite_ref-7" class="reference"><a href="cpp-language-exceptions.html#cite_note-7">[7]</a></sup><sup id="cite_ref-8" class="reference"><a href="cpp-language-exceptions.html#cite_note-8">[8]</a></sup><sup id="cite_ref-9" class="reference"><a href="cpp-language-exceptions.html#cite_note-9">[9]</a></sup></p>
|
|
<p>为避免不必要的异常对象复制和对象切片,catch 子句在实践中最好以引用捕获。<sup id="cite_ref-10" class="reference"><a href="cpp-language-exceptions.html#cite_note-10">[10]</a></sup><sup id="cite_ref-11" class="reference"><a href="cpp-language-exceptions.html#cite_note-11">[11]</a></sup><sup id="cite_ref-12" class="reference"><a href="cpp-language-exceptions.html#cite_note-12">[12]</a></sup><sup id="cite_ref-13" class="reference"><a href="cpp-language-exceptions.html#cite_note-13">[13]</a></sup></p>
|
|
<h3><span class="mw-headline" id=".E5.BC.95.E7.94.A8">引用</span></h3>
|
|
<ol class="references">
|
|
<li id="cite_note-1"><span class="mw-cite-backlink"><a href="cpp-language-exceptions.html#cite_ref-1">↑</a></span> <span class="reference-text">H. Sutter (2004) <a rel="nofollow" class="external text" href="http://www.drdobbs.com/when-and-how-to-use-exceptions/184401836">“何时及如何使用异常”</a>于 Dr. Dobb's</span></li>
|
|
<li id="cite_note-2"><span class="mw-cite-backlink"><a href="cpp-language-exceptions.html#cite_ref-2">↑</a></span> <span class="reference-text">H.Sutter, A. Alexandrescu (2004),“C++ 编码标准”,第 70 条</span></li>
|
|
<li id="cite_note-3"><span class="mw-cite-backlink"><a href="cpp-language-exceptions.html#cite_ref-3">↑</a></span> <span class="reference-text">C++ 核心指导方针 <a rel="nofollow" class="external text" href="https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#i10-use-exceptions-to-signal-a-failure-to-perform-a-required-task">I.10</a></span></li>
|
|
<li id="cite_note-4"><span class="mw-cite-backlink"><a href="cpp-language-exceptions.html#cite_ref-4">↑</a></span> <span class="reference-text">B. Stroustrup (2000),“C++ 程序语言” <a rel="nofollow" class="external text" href="http://stroustrup.com/3rd_safe.pdf">“附录 E”</a></span></li>
|
|
<li id="cite_note-5"><span class="mw-cite-backlink"><a href="cpp-language-exceptions.html#cite_ref-5">↑</a></span> <span class="reference-text">H. Sutter (2000) “Exceptional C++”</span></li>
|
|
<li id="cite_note-6"><span class="mw-cite-backlink"><a href="cpp-language-exceptions.html#cite_ref-6">↑</a></span> <span class="reference-text">D. Abrahams (2001) <a rel="nofollow" class="external text" href="http://www.boost.org/community/exception_safety.html">“泛型组件中的异常安全”</a></span></li>
|
|
<li id="cite_note-7"><span class="mw-cite-backlink"><a href="cpp-language-exceptions.html#cite_ref-7">↑</a></span> <span class="reference-text">D. Abrahams (2001) <a rel="nofollow" class="external text" href="http://www.boost.org/community/error_handling.html">“错误与异常处理”</a></span></li>
|
|
<li id="cite_note-8"><span class="mw-cite-backlink"><a href="cpp-language-exceptions.html#cite_ref-8">↑</a></span> <span class="reference-text">isocpp.org Super-FAQ <a rel="nofollow" class="external text" href="https://isocpp.org/wiki/faq/exceptions#what-to-throw">“我应该抛出什么?”</a></span></li>
|
|
<li id="cite_note-9"><span class="mw-cite-backlink"><a href="cpp-language-exceptions.html#cite_ref-9">↑</a></span> <span class="reference-text">C++ 核心指导方针 <a rel="nofollow" class="external text" href="https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#e14-use-purpose-designed-user-defined-types-as-exceptions-not-built-in-types">E.14</a></span></li>
|
|
<li id="cite_note-10"><span class="mw-cite-backlink"><a href="cpp-language-exceptions.html#cite_ref-10">↑</a></span> <span class="reference-text">C++ 核心指导方针 <a rel="nofollow" class="external text" href="https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#e15-catch-exceptions-from-a-hierarchy-by-reference">E.15</a></span></li>
|
|
<li id="cite_note-11"><span class="mw-cite-backlink"><a href="cpp-language-exceptions.html#cite_ref-11">↑</a></span> <span class="reference-text">S. Meyers (1996) “More Effective C++” 第 13 条</span></li>
|
|
<li id="cite_note-12"><span class="mw-cite-backlink"><a href="cpp-language-exceptions.html#cite_ref-12">↑</a></span> <span class="reference-text">isocpp.org 超级 FAQ <a rel="nofollow" class="external text" href="https://isocpp.org/wiki/faq/exceptions#what-to-catch">“我应该捕获什么?”</a></span></li>
|
|
<li id="cite_note-13"><span class="mw-cite-backlink"><a href="cpp-language-exceptions.html#cite_ref-13">↑</a></span> <span class="reference-text">H.Sutter, A. Alexandrescu (2004) “C++ 编码标准” 第 73 条</span></li>
|
|
</ol>
|
|
</div>
|
|
<div class="visualClear"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|