283 lines
34 KiB
HTML
283 lines
34 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_destructor 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>析构函数是<a href="cpp-language-lifetime.html">对象生存期</a>终结时调用的特殊<a href="cpp-language-member_functions.html">成员函数</a>。析构函数的目的是释放对象可能在其生存期间获得的资源。</p>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx20">
|
|
<td>
|
|
<p>析构函数不能是<a href="cpp-language-coroutines.html">协程</a>。</p>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<h3><span class="mw-headline" id=".E8.AF.AD.E6.B3.95">语法</span></h3>
|
|
<table class="t-sdsc-begin">
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
<tr class="t-sdsc">
|
|
<td><code><b>~</b></code> <span class="t-spar">类名</span> <code><b>();</b></code></td>
|
|
<td>(1)</td>
|
|
<td class="t-sdsc-nopad"></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
<tr class="t-sdsc">
|
|
<td><code><b>virtual</b></code> <code><b>~</b></code> <span class="t-spar">类名</span> <code><b>();</b></code></td>
|
|
<td>(2)</td>
|
|
<td class="t-sdsc-nopad"></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
<tr class="t-sdsc">
|
|
<td><span class="t-spar">声明说明符序列</span><span class="t-mark">(可选)</span> <code><b>~</b></code> <span class="t-spar">类名</span> <code><b>() = default;</b></code></td>
|
|
<td>(3)</td>
|
|
<td><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
<tr class="t-sdsc">
|
|
<td><span class="t-spar">声明说明符序列</span><span class="t-mark">(可选)</span> <code><b>~</b></code> <span class="t-spar">类名</span> <code><b>() = delete;</b></code></td>
|
|
<td>(4)</td>
|
|
<td><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
<tr class="t-sdsc">
|
|
<td><span class="t-spar">属性</span><span class="t-mark">(可选)</span> <span class="t-spar">声明说明符序列</span><span class="t-mark">(可选)</span> <span class="t-spar">标识表达式</span> <code><b>(</b></code> <code><b>void</b></code><span class="t-mark">(可选)</span> <code><b>)</b></code> <span class="t-spar">异常说明</span><span class="t-mark">(可选)</span> <span class="t-spar">requires子句</span><span class="t-mark">(可选)</span> <span class="t-spar">属性</span><span class="t-mark">(可选)</span> <code><b>;</b></code></td>
|
|
<td>(5)</td>
|
|
<td class="t-sdsc-nopad"></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
</table>
|
|
<div class="t-li1"><span class="t-li">1)</span> <span class="t-rev-inl t-since-cxx20"><span>预期的</span> <span><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></span></span>析构函数的典型声明</div>
|
|
<div class="t-li1"><span class="t-li">2)</span> 虚析构函数在基类中常为必要的</div>
|
|
<div class="t-li1"><span class="t-li">3)</span> 强迫编译器生成析构函数</div>
|
|
<div class="t-li1"><span class="t-li">4)</span> 禁用隐式析构函数</div>
|
|
<div class="t-li1"><span class="t-li">5)</span> <span class="t-rev-inl t-since-cxx20"><span>预期的</span> <span><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></span></span>析构函数声明的正式语法</div>
|
|
<table class="t-par-begin">
|
|
<tr class="t-par">
|
|
<td><span class="t-spar">声明说明符序列</span></td>
|
|
<td>-</td>
|
|
<td><code>friend</code>、<code>inline</code>、<code>virtual</code><span class="t-rev-inl t-since-cxx20"><span>、<code>constexpr</code>、<code>consteval</code></span> <span><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></span></span></td>
|
|
</tr>
|
|
<tr class="t-par">
|
|
<td><span class="t-spar">标识表达式</span></td>
|
|
<td>-</td>
|
|
<td>在类定义中时,为符号 <code><b>~</b></code> 后随 <span class="t-spar">类名</span>。在类模板中时,为符号 <code><b>~</b></code> 后随模板当前实例化的名字。在命名空间作用域,或在另一类的<a href="cpp-language-friend.html">友元</a>声明中时,为 <i>嵌套名说明符</i> 后随符号 <code><b>~</b></code> 再后随与 <span class="t-spar">嵌套名说明符</span> 所指名者相同的 <span class="t-spar">类名</span>。该名字在任何情况下都必须是类或模板的实际名字,而非 typedef。可以用不改变其含义的括号环绕整个 <span class="t-spar">标识表达式</span>。</td>
|
|
</tr>
|
|
<tr class="t-par">
|
|
<td><span class="t-spar">属性</span></td>
|
|
<td>-</td>
|
|
<td><span class="t-mark-rev t-since-cxx11">(C++11 起)</span> 可选的任意数量<a href="cpp-language-attributes.html">属性</a>序列</td>
|
|
</tr>
|
|
<tr class="t-par">
|
|
<td><span class="t-spar">异常说明</span></td>
|
|
<td>-</td>
|
|
<td>与在任何函数声明中一样的异常说明(<span class="t-rev-inl t-until-cxx17"><span><a href="cpp-language-except_spec.html">动态异常说明</a></span> <span><span class="t-mark-rev t-until-cxx17">(C++17 前)</span></span></span>或 <span class="t-rev-inl t-since-cxx11"><span><a href="cpp-language-noexcept_spec.html">noexcept 说明</a></span> <span><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></span></span> 之一)
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx11">
|
|
<td>
|
|
<p>在有显式提供异常说明时,其异常说明被认为是隐式声明的析构函数(见下文)可能所用的异常说明之一。它大多数情况下是 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw1">noexcept</span><span class="br0">(</span><span class="kw2">true</span><span class="br0">)</span></span></span>。因此抛出异常的析构函数必须显式声明为 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw1">noexcept</span><span class="br0">(</span><span class="kw2">false</span><span class="br0">)</span></span></span>。</p>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
</td>
|
|
</tr>
|
|
<tr class="t-par">
|
|
<td><span class="t-spar">requires子句</span></td>
|
|
<td>-</td>
|
|
<td><span class="t-mark-rev t-since-cxx20">(C++20 起)</span> 声明预期析构函数的关联<a href="cpp-language-constraints.html">约束</a>的 requires 子句,为使得预期析构函数被选为析构函数,它必须得到满足</td>
|
|
</tr>
|
|
</table>
|
|
<h3><span class="mw-headline" id=".E8.A7.A3.E9.87.8A">解释</span></h3>
|
|
<p>每当对象的<a href="cpp-language-lifetime.html">生存期</a>结束时都会调用析构函数,时间点包含:</p>
|
|
<ul>
|
|
<li><a href="cpp-utility-program-exit.html">程序终止</a>,对于具有静态<a href="cpp-language-storage_duration.html">存储期</a>的对象</li>
|
|
</ul>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx11">
|
|
<td>
|
|
<ul>
|
|
<li>退出线程,对于具有线程局部存储期的对象</li>
|
|
</ul>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<ul>
|
|
<li>作用域结束,对于具有自动存储期的对象和生存期因绑定到引用而延长的临时量</li>
|
|
<li><a href="cpp-language-delete.html">delete 表达式</a>,对于具有动态存储期的对象</li>
|
|
<li>完整<a href="cpp-language-expressions.html">表达式</a>的结尾,对于无名临时量</li>
|
|
<li><a href="cpp-language-throw.html">栈回溯</a>,对于具有自动存储期的对象,当未捕捉的异常脱离其块时。</li>
|
|
</ul>
|
|
<p>析构函数也可以直接调用,例如销毁用<a href="cpp-language-new.html">布置 new</a> 或通过分配器成员函数(如 <a href="cpp-memory-allocator-destroy.html"><tt>std::allocator::destroy()</tt></a>)构造的对象。注意,对普通对象(如局部变量)直接调用析构函数会导致在作用域结束处再次调用析构函数时引发未定义行为。</p>
|
|
<p>在泛型语境中,析构函数调用语法可以用于非类类型的对象;这被称为伪析构函数调用:见<a href="cpp-language-operator_member_access.html#.E5.86.85.E5.BB.BA.E7.9A.84.E6.88.90.E5.91.98.E8.AE.BF.E9.97.AE.E8.BF.90.E7.AE.97.E7.AC.A6">成员访问运算符</a>。</p>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx20">
|
|
<td>
|
|
<h3><span class="mw-headline" id=".E9.A2.84.E6.9C.9F.E7.9A.84.E6.9E.90.E6.9E.84.E5.87.BD.E6.95.B0">预期的析构函数</span></h3>
|
|
<p>一个类可以有一个或多个预期的析构函数,其中之一会被选为类的析构函数。</p>
|
|
<p>为确定哪个预期的析构函数是析构函数,<a href="cpp-language-overload_resolution.html">重载决议</a>会在类定义的末尾以空实参列表,在类中声明的潜在析构函数之间进行。如果重载决议失败,那么程序为谬构。析构函数选择不会 <a href="cpp-language-definition.html#.E5.8D.95.E4.B8.80.E5.AE.9A.E4.B9.89.E8.A7.84.E5.88.99.EF.BC.88ODR.EF.BC.89">odr 式使用</a>选中的析构函数,而且选择的析构函数可以是弃置的。</p>
|
|
<p>所有预期的析构函数都是特殊成员函数。如果不对类 <code>T</code> 提供用户声明的预期的析构函数,那么编译器总是会声明一个(见后述),而该隐式声明的预期析构函数也是 <code>T</code> 的析构函数。</p>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<h3><span class="mw-headline" id=".E9.9A.90.E5.BC.8F.E5.A3.B0.E6.98.8E.E7.9A.84.E6.9E.90.E6.9E.84.E5.87.BD.E6.95.B0">隐式声明的析构函数</span></h3>
|
|
<p>如果不向<a href="cpp-language-class.html">类类型</a>(<span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw1">struct</span></span></span>、<span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw1">class</span></span></span> 或 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw1">union</span></span></span>)提供用户声明的析构函数,那么编译器总是会声明一个析构函数作为这个类的 <code>inline public</code> 成员。</p>
|
|
<p>与任何隐式声明的特殊成员函数相同,隐式声明的析构函数的异常说明是不抛出的,除非<span class="t-rev-inl t-since-cxx17"><span>任何潜在构造的基类或成员的析构函数是<a href="cpp-language-noexcept_spec.html">潜在抛出</a>的</span> <span><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></span></span><span class="t-rev-inl t-until-cxx17"><span>隐式定义会直接调用有不同异常说明的函数</span> <span><span class="t-mark-rev t-until-cxx17">(C++17 前)</span></span></span>。实践上,隐式的析构函数是 <code>noexcept</code> 的,除非该类被析构函数为 <code>noexcept(false)</code> 的基类或成员所“毒害”。</p>
|
|
<h3><span class="mw-headline" id=".E5.BC.83.E7.BD.AE.E7.9A.84.E9.9A.90.E5.BC.8F.E5.A3.B0.E6.98.8E.E7.9A.84.E6.9E.90.E6.9E.84.E5.87.BD.E6.95.B0">弃置的隐式声明的析构函数</span></h3>
|
|
<p>如果满足下列任一条件,那么类 <code>T</code> 的隐式声明或预置的析构函数<span class="t-rev-inl t-until-cxx11"><span>不会被定义</span> <span><span class="t-mark-rev t-until-cxx11">(C++11 前)</span></span></span><span class="t-rev-inl t-since-cxx11"><span>被定义为<i>弃置的</i></span> <span><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></span></span>:</p>
|
|
<ul>
|
|
<li><code>T</code> 拥有无法销毁(拥有被弃置或不可访问的析构函数)的非静态数据成员</li>
|
|
<li><code>T</code> 拥有无法销毁(拥有被弃置或不可访问的析构函数)的直接或虚基类</li>
|
|
</ul>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx11">
|
|
<td>
|
|
<ul>
|
|
<li><code>T</code> 是联合体并拥有带非平凡析构函数的变体成员。</li>
|
|
</ul>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<ul>
|
|
<li>隐式声明的析构函数是虚函数(因为基类有虚析构函数),且对解分配函数(<span class="t-c"><span class="mw-geshi cpp source-cpp"><a href="cpp-memory-new-operator_delete.html"><span class="kw689">operator delete</span></a><span class="br0">(</span><span class="br0">)</span></span></span>)的查找导致对有歧义、被弃置或不可访问函数的调用。</li>
|
|
</ul>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx20">
|
|
<td>
|
|
<p>如果预置的 <code>T</code> 的预期析构函数不是 <code>T</code> 的析构函数,那么它被定义为弃置的。</p>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<h3><span class="mw-headline" id=".E5.B9.B3.E5.87.A1.E6.9E.90.E6.9E.84.E5.87.BD.E6.95.B0">平凡析构函数</span></h3>
|
|
<p>如果满足下列全部条件,那么 <code>T</code> 的析构函数是平凡的:</p>
|
|
<ul>
|
|
<li>析构函数不是用户提供的(表示它是隐式声明,或在其首个声明显式定义为预置的)</li>
|
|
<li>析构函数非虚(即基类析构函数非虚)</li>
|
|
<li>所有直接基类都拥有平凡析构函数</li>
|
|
<li>所有类类型(或类的数组类型)的非静态数据成员都拥有平凡析构函数</li>
|
|
</ul>
|
|
<p>平凡析构函数是不进行任何动作的析构函数。有平凡析构函数的对象不要求 delete 表达式,并可以通过简单地解分配其存储进行释放。所有与 C 语言兼容的数据类型(POD 类型)都是可以平凡析构的。</p>
|
|
<h3><span class="mw-headline" id=".E9.9A.90.E5.BC.8F.E5.AE.9A.E4.B9.89.E7.9A.84.E6.9E.90.E6.9E.84.E5.87.BD.E6.95.B0">隐式定义的析构函数</span></h3>
|
|
<p>如果隐式声明的析构函数没有被弃置,那么当它被 <a href="cpp-language-definition.html#ODR_.E5.BC.8F.E4.BD.BF.E7.94.A8">ODR 式使用</a>时,它会被编译器隐式定义(即生成并编译函数体)。这个隐式定义的析构函数拥有空的函数体。<span class="t-rev-inl t-since-cxx20"><span>如果生成的析构函数满足 <a href="cpp-language-constexpr.html">constexpr 析构函数</a>的要求,那么它是 <code>constexpr</code> 的。</span> <span><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></span></span></p>
|
|
<h3><span class="mw-headline" id=".E6.9E.90.E6.9E.84.E5.BA.8F.E5.88.97">析构序列</span></h3>
|
|
<p>对于用户定义或隐式定义的析构函数,在析构函数体执行后,编译器会以声明的逆序调用该类的所有非静态非变体成员的析构函数,然后以<a href="cpp-language-initializer_list.html#.E5.88.9D.E5.A7.8B.E5.8C.96.E9.A1.BA.E5.BA.8F" class="mw-redirect">构造的逆序</a>调用所有直接非虚基类的析构函数(继而调用其成员与其基类的析构函数,以此类推),最后,如果此对象类型为最终派生类,那么调用所有虚基类的析构函数。</p>
|
|
<p>即便在直接调用析构函数时(例如 <span class="t-c"><span class="mw-geshi cpp source-cpp">obj.~Foo<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span></span></span>),<span class="t-c"><span class="mw-geshi cpp source-cpp">~Foo<span class="br0">(</span><span class="br0">)</span></span></span> 中的 return 语句也不会立即将控制返回到调用方:它首先调用其所有成员及基类的析构函数。</p>
|
|
<h3><span class="mw-headline" id=".E8.99.9A.E6.9E.90.E6.9E.84.E5.87.BD.E6.95.B0">虚析构函数</span></h3>
|
|
<p>通过指向基类的指针删除对象会引发未定义行为,除非基类的析构函数是<a href="cpp-language-virtual.html">虚函数</a>:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">class</span> Base <span class="br0">{</span>
|
|
<span class="kw1">public</span><span class="sy4">:</span>
|
|
<span class="kw1">virtual</span> ~Base<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span><span class="br0">}</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw1">class</span> Derived <span class="sy4">:</span> <span class="kw1">public</span> Base <span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span>
|
|
Base<span class="sy2">*</span> b <span class="sy1">=</span> new Derived<span class="sy4">;</span>
|
|
delete b<span class="sy4">;</span> <span class="co1">// 安全</span></pre></div>
|
|
</div>
|
|
<p>一条常用方针是,基类的析构函数必须<a rel="nofollow" class="external text" href="http://www.gotw.ca/publications/mill18.htm">是公开且虚或受保护且非虚之一</a></p>
|
|
<h3><span class="mw-headline" id=".E7.BA.AF.E8.99.9A.E6.9E.90.E6.9E.84.E5.87.BD.E6.95.B0">纯虚析构函数</span></h3>
|
|
<p><span class="t-rev-inl t-since-cxx20"><span>预期的</span> <span><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></span></span>析构函数可以声明为<a href="cpp-language-abstract_class.html">纯虚</a>的,例如对于需要声明为抽象类,但没有其他可声明为纯虚的适合函数的基类。纯虚析构函数必须有定义,因为在销毁派生类时,所有基类析构函数都会被调用:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">class</span> AbstractBase <span class="br0">{</span>
|
|
<span class="kw1">public</span><span class="sy4">:</span>
|
|
<span class="kw1">virtual</span> ~AbstractBase<span class="br0">(</span><span class="br0">)</span> <span class="sy1">=</span> <span class="nu0">0</span><span class="sy4">;</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
AbstractBase<span class="sy4">::</span>~AbstractBase<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span><span class="br0">}</span>
|
|
<span class="kw1">class</span> Derived <span class="sy4">:</span> <span class="kw1">public</span> AbstractBase <span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="co1">// AbstractBase obj; // 编译错误</span>
|
|
Derived obj<span class="sy4">;</span> <span class="co1">// OK</span></pre></div>
|
|
</div>
|
|
<h3><span class="mw-headline" id=".E5.BC.82.E5.B8.B8">异常</span></h3>
|
|
<p>与其他函数一样,析构函数可以通过抛出<a href="cpp-language-exceptions.html">异常</a>终止<span class="t-rev-inl t-since-cxx11"><span>(这通常要求将它明确声明为 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw1">noexcept</span><span class="br0">(</span><span class="kw2">false</span><span class="br0">)</span></span></span>)</span> <span><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></span></span>,然而如果恰好在<a href="cpp-language-throw.html">栈回溯</a>期间调用析构函数,那么会改为调用 <span class="t-lc"><a href="cpp-error-terminate.html">std::terminate</a></span>。</p>
|
|
<p>虽然有时候可以用 <span class="t-lc"><a href="cpp-error-uncaught_exception.html">std::uncaught_exception</a></span> 来检测进展中的栈回溯,但允许任何析构函数通过抛异常终止通常被认为是坏的实践。尽管如此,一些库(如 <a rel="nofollow" class="external text" href="https://github.com/SOCI/soci">SOCI</a> 与 <a rel="nofollow" class="external text" href="http://galeracluster.com/downloads/">Galera 3</a> 等)仍然使用了这项功能,它们利用了无名临时量的析构函数的能力,以在构造该临时量的完整表达式结束处抛异常。</p>
|
|
<p>库基础 TS v3 中的 <a href="cpp-experimental-scope_success.html"><tt>std::experimental::scope_success</tt></a> 可以拥有<a href="cpp-experimental-scope_success-~scope_success.html">潜在抛出的析构函数</a>,它在正常退出作用域且退出函数抛异常时抛出异常。</p>
|
|
<h3><span class="mw-headline" id=".E7.A4.BA.E4.BE.8B">示例</span></h3>
|
|
<div class="t-example">
|
|
<div class="t-example-live-link"></div>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="co2">#include <iostream></span>
|
|
|
|
<span class="kw1">struct</span> A
|
|
<span class="br0">{</span>
|
|
<span class="kw4">int</span> i<span class="sy4">;</span>
|
|
|
|
A <span class="br0">(</span> <span class="kw4">int</span> i <span class="br0">)</span> <span class="sy4">:</span> i <span class="br0">(</span> i <span class="br0">)</span>
|
|
<span class="br0">{</span>
|
|
<a href="cpp-io-cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1"><<</span> <span class="st0">"构造 a"</span> <span class="sy1"><<</span> i <span class="sy1"><<</span> <span class="st0">'<span class="es1">\n</span>'</span><span class="sy4">;</span>
|
|
<span class="br0">}</span>
|
|
|
|
~A<span class="br0">(</span><span class="br0">)</span>
|
|
<span class="br0">{</span>
|
|
<a href="cpp-io-cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1"><<</span> <span class="st0">"析构 a"</span> <span class="sy1"><<</span> i <span class="sy1"><<</span> <span class="st0">'<span class="es1">\n</span>'</span><span class="sy4">;</span>
|
|
<span class="br0">}</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
|
|
A a0<span class="br0">(</span><span class="nu0">0</span><span class="br0">)</span><span class="sy4">;</span>
|
|
|
|
<span class="kw4">int</span> main<span class="br0">(</span><span class="br0">)</span>
|
|
<span class="br0">{</span>
|
|
A a1<span class="br0">(</span><span class="nu0">1</span><span class="br0">)</span><span class="sy4">;</span>
|
|
A<span class="sy2">*</span> p<span class="sy4">;</span>
|
|
|
|
<span class="br0">{</span> <span class="co1">// 嵌套的作用域</span>
|
|
A a2<span class="br0">(</span><span class="nu0">2</span><span class="br0">)</span><span class="sy4">;</span>
|
|
p <span class="sy1">=</span> new A<span class="br0">(</span><span class="nu0">3</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="br0">}</span> <span class="co1">// a2 离开作用域</span>
|
|
|
|
delete p<span class="sy4">;</span> <span class="co1">// 调用 a3 的析构函数</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
<p>输出:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="text source-text">
|
|
<pre class="de1">构造 a0
|
|
构造 a1
|
|
构造 a2
|
|
构造 a3
|
|
析构 a2
|
|
析构 a3
|
|
析构 a1
|
|
析构 a0</pre></div>
|
|
</div>
|
|
</div>
|
|
<h3><span class="mw-headline" id=".E5.8F.82.E9.98.85">参阅</span></h3>
|
|
<ul>
|
|
<li><a href="cpp-language-copy_elision.html">复制消除</a></li>
|
|
<li><a href="cpp-language-new.html"><code>new</code></a></li>
|
|
<li><a href="cpp-language-delete.html"><code>delete</code></a></li>
|
|
</ul>
|
|
</div>
|
|
<div class="visualClear"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|