351 lines
42 KiB
HTML
351 lines
42 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_reference_initialization 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>
|
|
<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>
|
|
<p><span class="t-spar">T</span> <code><b>&</b></code> <span class="t-spar">引用</span> <code><b>=</b></code> <span class="t-spar">目标</span> <code><b>;</b></code></p>
|
|
<p><span class="t-spar">T</span> <code><b>&</b></code> <span class="t-spar">引用</span> <code><b>=</b></code> <code><b>{</b></code> <span class="t-spar">实参1, 实参2, ...</span> <code><b>};</b></code></p>
|
|
<p><span class="t-spar">T</span> <code><b>&</b></code> <span class="t-spar">引用</span> <code><b>(</b></code> <span class="t-spar">目标</span> <code><b>)</b></code> <code><b>;</b></code></p>
|
|
<p><span class="t-spar">T</span> <code><b>&</b></code> <span class="t-spar">引用</span> <code><b>{</b></code> <span class="t-spar">实参1, 实参2, ...</span> <code><b>}</b></code> <code><b>;</b></code></p>
|
|
</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>
|
|
<p><span class="t-spar">T</span> <code><b>&&</b></code> <span class="t-spar">引用</span> <code><b>=</b></code> <span class="t-spar">目标</span> <code><b>;</b></code></p>
|
|
<p><span class="t-spar">T</span> <code><b>&&</b></code> <span class="t-spar">引用</span> <code><b>=</b></code> <code><b>{</b></code> <span class="t-spar">实参1, 实参2, ...</span> <code><b>};</b></code></p>
|
|
<p><span class="t-spar">T</span> <code><b>&&</b></code> <span class="t-spar">引用</span> <code><b>(</b></code> <span class="t-spar">目标</span> <code><b>)</b></code> <code><b>;</b></code></p>
|
|
<p><span class="t-spar">T</span> <code><b>&&</b></code> <span class="t-spar">引用</span> <code><b>{</b></code> <span class="t-spar">实参1, 实参2, ...</span> <code><b>}</b></code> <code><b>;</b></code></p>
|
|
</td>
|
|
<td>(2)</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">R</span> <span class="t-spar">函数</span> <code><b>(</b></code> <span class="t-spar">T</span> <code><b>&</b></code> <span class="t-spar">实参</span> <code><b>);</b></code> <span class="t-rev-inl t-since-cxx11"><span>或 <span class="t-spar">R</span> <span class="t-spar">函数</span> <code><b>(</b></code> <span class="t-spar">T</span> <code><b>&&</b></code> <span class="t-spar">实参</span> <code><b>);</b></code></span> <span><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></span></span>
|
|
<p><span class="t-spar">函数</span> <code><b>(</b></code> <span class="t-spar">目标</span> <code><b>)</b></code></p>
|
|
<p><span class="t-spar">函数</span> <code><b>(</b></code> <code><b>{</b></code> <span class="t-spar">实参1, 实参2, ...</span> <code><b>}</b></code> <code><b>)</b></code></p>
|
|
</td>
|
|
<td>(3)</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">T</span> <code><b>&</b></code> <span class="t-spar">函数</span> <code><b>()</b></code> <span class="t-rev-inl t-since-cxx11"><span>或 <span class="t-spar">T</span> <code><b>&&</b></code> <span class="t-spar">函数</span> <code><b>()</b></code></span> <span><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></span></span> 内
|
|
<p><code><b>return</b></code> <span class="t-spar">目标</span> <code><b>;</b></code></p>
|
|
</td>
|
|
<td>(4)</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-spar">T</span> <code><b>&</b></code> <span class="t-spar">引用</span> <code><b>;</b></code> <span class="t-rev-inl t-since-cxx11"><span>或 <span class="t-spar">T</span> <code><b>&&</b></code> <span class="t-spar">引用</span> <code><b>;</b></code></span> <span><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></span></span>
|
|
<p><span class="t-spar">类</span><code><b>::</b></code><span class="t-spar">类(...)</span> <code><b>:</b></code> <span class="t-spar">引用</span><code><b>(</b></code> <span class="t-spar">目标</span><code><b>)</b></code> {...}</p>
|
|
</td>
|
|
<td>(5)</td>
|
|
<td class="t-sdsc-nopad"></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
</table>
|
|
<h3><span class="mw-headline" id=".E8.A7.A3.E9.87.8A">解释</span></h3>
|
|
<p>到 <code>T</code> 的引用能以 <code>T</code> 类型的对象、<code>T</code> 类型的函数或可隐式转换到 <code>T</code> 的对象初始化。引用一旦初始化,便无法引用另一对象。</p>
|
|
<p>引用在下列情形初始化:</p>
|
|
<div class="t-li1"><span class="t-li">1)</span> 以初始化器声明具名<a href="cpp-language-reference.html#.E5.B7.A6.E5.80.BC.E5.BC.95.E7.94.A8">左值引用</a>变量时</div>
|
|
<div class="t-li1"><span class="t-li">2)</span> 以初始化器声明具名<a href="cpp-language-reference.html#.E5.8F.B3.E5.80.BC.E5.BC.95.E7.94.A8">右值引用</a>变量时</div>
|
|
<div class="t-li1"><span class="t-li">3)</span> 在函数调用表达式中且有函数形参拥有引用类型时</div>
|
|
<div class="t-li1"><span class="t-li">4)</span> 在函数的 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw1">return</span></span></span> 语句中且函数返回引用类型时</div>
|
|
<div class="t-li1"><span class="t-li">5)</span> 以<a href="cpp-language-initializer_list.html" class="mw-redirect">成员初始化器</a>初始化引用类型的<a href="cpp-language-data_members.html">非静态数据成员</a>时</div>
|
|
<p>引用初始化的效果是:</p>
|
|
<ul>
|
|
<li>如果初始化器是花括号初始化器列表 <code><b>{</b></code> <span class="t-spar">实参1, 实参2, ...</span> <code><b>}</b></code> ,那么遵循<a href="cpp-language-list_initialization.html">列表初始化</a>。</li>
|
|
</ul>
|
|
<ul>
|
|
<li>否则,如果引用是左值引用:</li>
|
|
</ul>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>如果 <span class="t-spar">目标</span> 是左值表达式,且其类型为 <code>T</code> 或派生于 <code>T</code>,而且有相等或更少的 cv 限定,那么引用被绑定到左值表达式所标识的对象或其基类子对象。</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw4">double</span> d <span class="sy1">=</span> <span class="nu16">2.0</span><span class="sy4">;</span>
|
|
<span class="kw4">double</span><span class="sy3">&</span> rd <span class="sy1">=</span> d<span class="sy4">;</span> <span class="co1">// rd 引用 d</span>
|
|
<span class="kw4">const</span> <span class="kw4">double</span><span class="sy3">&</span> rcd <span class="sy1">=</span> d<span class="sy4">;</span> <span class="co1">// rcd 引用 d</span>
|
|
<span class="kw1">struct</span> A <span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw1">struct</span> B <span class="sy4">:</span> A <span class="br0">{</span><span class="br0">}</span> b<span class="sy4">;</span>
|
|
A<span class="sy3">&</span> ra <span class="sy1">=</span> b<span class="sy4">;</span> <span class="co1">// ra 引用 b 中的 A 子对象</span>
|
|
<span class="kw4">const</span> A<span class="sy3">&</span> rca <span class="sy1">=</span> b<span class="sy4">;</span> <span class="co1">// rca 引用 b 中的 A 子对象</span></pre></div>
|
|
</div>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>否则,如果 <span class="t-spar">目标</span> 的类型与 <code>T</code> 不相同且不从它派生,且 <span class="t-spar">目标</span> 拥有到类型为 <code>T</code> 或派生于 <code>T</code> 并有相等或更少的 cv 限定的左值的转换函数,那么绑定引用到转换函数所返回的左值所标识的对象(或到其基类子对象)。</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">struct</span> A <span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw1">struct</span> B <span class="sy4">:</span> A <span class="br0">{</span> operator <span class="kw4">int</span><span class="sy3">&</span><span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw4">int</span><span class="sy3">&</span> ir <span class="sy1">=</span> B<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// ir 指代 B::operator int& 的结果</span></pre></div>
|
|
</div>
|
|
<ul>
|
|
<li>否则,如果引用是到非 volatile 的 const 限定类型的左值引用<span class="t-rev-inl t-since-cxx11"><span>或右值引用</span> <span><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></span></span>:</li>
|
|
</ul>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>如果 <span class="t-spar">目标</span> 是非位域右值或函数左值,且其类型是 <code>T</code> 或派生于 <code>T</code> ,并拥有相等或更少 cv 限定,那么绑定引用到初始化器表达式的值或其基类子对象<span class="t-rev-inl t-since-cxx17"><span>(如果需要,先进行<a href="cpp-language-implicit_conversion.html#.E4.B8.B4.E6.97.B6.E9.87.8F.E5.AE.9E.E8.B4.A8.E5.8C.96">临时量实质化</a>)</span> <span><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></span></span>。</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">struct</span> A <span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw1">struct</span> B <span class="sy4">:</span> A <span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw4">extern</span> B f<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="kw4">const</span> A<span class="sy3">&</span> rca2 <span class="sy1">=</span> f<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 到 B 右值的 A 子对象。</span>
|
|
A<span class="sy3">&&</span> rra <span class="sy1">=</span> f<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 同上</span>
|
|
|
|
<span class="kw4">int</span> i2 <span class="sy1">=</span> <span class="nu0">42</span><span class="sy4">;</span>
|
|
<span class="kw4">int</span><span class="sy3">&&</span> rri <span class="sy1">=</span> <span class="kw1">static_cast</span><span class="sy1"><</span><span class="kw4">int</span><span class="sy3">&&</span><span class="sy1">></span><span class="br0">(</span>i2<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 直接绑定到 i2</span></pre></div>
|
|
</div>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>否则,如果 <span class="t-spar">目标</span> 的类型与 <code>T</code> 不相同且不从它派生,且 <span class="t-spar">目标</span> 拥有到类型为 <code>T</code> 或派生于 <code>T</code> 并有相等或更少的 cv 限定的右值或函数左值的转换函数,那么绑定引用到转换函数的结果或到其基类子对象<span class="t-rev-inl t-since-cxx17"><span>(如果需要,先进行<a href="cpp-language-implicit_conversion.html#.E4.B8.B4.E6.97.B6.E9.87.8F.E5.AE.9E.E8.B4.A8.E5.8C.96">临时量实质化</a>)</span> <span><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></span></span>。</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">struct</span> A <span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw1">struct</span> B <span class="sy4">:</span> A <span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw1">struct</span> X <span class="br0">{</span> operator B<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="br0">}</span> x<span class="sy4">;</span>
|
|
<span class="kw4">const</span> A<span class="sy3">&</span> r <span class="sy1">=</span> x<span class="sy4">;</span> <span class="co1">// 绑定到转换结果的 A 子对象</span>
|
|
B<span class="sy3">&&</span> rrb <span class="sy1">=</span> x<span class="sy4">;</span> <span class="co1">// 直接绑定到转换的结果</span></pre></div>
|
|
</div>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>否则,将 <span class="t-spar">目标</span> 隐式转换为 <code>T</code>。绑定引用到转换<span class="t-rev-inl t-since-cxx17"><span>(在<a href="cpp-language-implicit_conversion.html#.E4.B8.B4.E6.97.B6.E9.87.8F.E5.AE.9E.E8.B4.A8.E5.8C.96">实质化临时量</a>后,即使 <code>T</code> 是标量类型也保持其 cv 限定)</span> <span><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></span></span>的结果。如果 <span class="t-spar">目标</span>(或如果由用户定义转换函数进行转换,则为转换函数的结果)类型为 <code>T</code> 或派生于 <code>T</code>,那么它必须拥有等于或少于 <code>T</code> 的 cv 限定<span class="t-rev-inl t-since-cxx11"><span>,且如果引用为右值引用,那么它必须不是左值</span> <span><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></span></span>。</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw4">const</span> <a href="cpp-string-basic_string.html"><span class="kw1230">std::<span class="me2">string</span></span></a><span class="sy3">&</span> rs <span class="sy1">=</span> <span class="st0">"abc"</span><span class="sy4">;</span> <span class="co1">// rs 指代从字符数组复制初始化的临时量</span>
|
|
<span class="kw4">const</span> <span class="kw4">double</span><span class="sy3">&</span> rcd2 <span class="sy1">=</span> <span class="nu0">2</span><span class="sy4">;</span> <span class="co1">// rcd2 指代值为 2.0 的临时量</span>
|
|
<span class="kw4">int</span> i3 <span class="sy1">=</span> <span class="nu0">2</span><span class="sy4">;</span>
|
|
<span class="kw4">double</span><span class="sy3">&&</span> rrd3 <span class="sy1">=</span> i3<span class="sy4">;</span> <span class="co1">// rrd3 指代值为 2.0 的临时量</span></pre></div>
|
|
</div>
|
|
<h3><span class="mw-headline" id=".E4.B8.B4.E6.97.B6.E9.87.8F.E7.94.9F.E5.AD.98.E6.9C.9F">临时量生存期</span></h3>
|
|
<p>一旦引用被绑定到临时对象或其子对象,临时对象的生存期就被延续以匹配引用的生存期(检查<a href="cpp-language-lifetime.html#.E4.B8.B4.E6.97.B6.E5.AF.B9.E8.B1.A1.E7.94.9F.E5.AD.98.E6.9C.9F">临时对象生存期的例外</a>),其中临时对象或其子对象由下列表达式之一代表:</p>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-until-cxx17">
|
|
<td>
|
|
<ul>
|
|
<li>对象类型的<a href="cpp-language-value_category.html#.E7.BA.AF.E5.8F.B3.E5.80.BC">纯右值</a>表达式、</li>
|
|
</ul>
|
|
</td>
|
|
<td><span class="t-mark-rev t-until-cxx17">(C++17 前)</span></td>
|
|
</tr>
|
|
<tr class="t-rev t-since-cxx17">
|
|
<td>
|
|
<ul>
|
|
<li><a href="cpp-language-implicit_conversion.html#.E4.B8.B4.E6.97.B6.E9.87.8F.E5.AE.9E.E8.B4.A8.E5.8C.96">临时量实质化转换</a>、</li>
|
|
</ul>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<ul>
|
|
<li>有括号表达式 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="br0">(</span>e<span class="br0">)</span></span></span>,其中 <span class="t-c"><span class="mw-geshi cpp source-cpp">e</span></span> 是这些表达式之一、</li>
|
|
<li>形式为 <span class="t-c"><span class="mw-geshi cpp source-cpp">a<span class="br0">[</span>n<span class="br0">]</span></span></span> 或 <span class="t-c"><span class="mw-geshi cpp source-cpp">n<span class="br0">[</span>a<span class="br0">]</span></span></span> 的<a href="cpp-language-operator_member_access.html#.E5.86.85.E5.BB.BA.E7.9A.84.E4.B8.8B.E6.A0.87.E8.BF.90.E7.AE.97.E7.AC.A6">内建的下标表达式</a>,其中 <span class="t-c"><span class="mw-geshi cpp source-cpp">a</span></span> 是数组且为这些表达式之一、</li>
|
|
<li>形式为 <span class="t-c"><span class="mw-geshi cpp source-cpp">e.<span class="me1">m</span></span></span> 的<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>,其中 <span class="t-c"><span class="mw-geshi cpp source-cpp">e</span></span> 是这些表达式之一而 <span class="t-c"><span class="mw-geshi cpp source-cpp">m</span></span> 指代对象类型的非静态数据成员、</li>
|
|
<li>形式为 <span class="t-c"><span class="mw-geshi cpp source-cpp">e.<span class="sy2">*</span>mp</span></span> 的<a href="cpp-language-operator_member_access.html#.E5.86.85.E5.BB.BA.E7.9A.84.E6.88.90.E5.91.98.E6.8C.87.E9.92.88.E8.AE.BF.E9.97.AE.E8.BF.90.E7.AE.97.E7.AC.A6">成员指针操作</a>,其中 <span class="t-c"><span class="mw-geshi cpp source-cpp">e</span></span> 是这些表达式之一而 <span class="t-c"><span class="mw-geshi cpp source-cpp">mp</span></span> 是指向数据成员的指针、</li>
|
|
<li>无用户定义转换的 <a href="cpp-language-const_cast.html"><code>const_cast</code></a>、 <a href="cpp-language-static_cast.html"><code>static_cast</code></a>、 <a href="cpp-language-dynamic_cast.html"><code>dynamic_cast</code></a> 或 <a href="cpp-language-reinterpret_cast.html"><code>reinterpret_cast</code></a> 转换,它将这些表达式之一转换成指代操作数所指代的对象,其完整对象,或完整对象的子对象的泛左值(<a href="cpp-language-explicit_cast.html">显式转型</a>表达式被转译成这些基础转型的序列)、</li>
|
|
<li>形式为 <span class="t-c"><span class="mw-geshi cpp source-cpp">cond <span class="sy4">?</span> e1 <span class="sy4">:</span> e2</span></span> 并为泛左值的<a href="cpp-language-operator_other.html#.E6.9D.A1.E4.BB.B6.E8.BF.90.E7.AE.97.E7.AC.A6">条件表达式</a>,其中 <span class="t-c"><span class="mw-geshi cpp source-cpp">e1</span></span> 或 <span class="t-c"><span class="mw-geshi cpp source-cpp">e2</span></span> 为这些表达式之一,或</li>
|
|
<li>形式为 <span class="t-c"><span class="mw-geshi cpp source-cpp">x, e</span></span> 并为泛左值的<a href="cpp-language-operator_other.html#.E5.86.85.E5.BB.BA.E7.9A.84.E9.80.97.E5.8F.B7.E8.BF.90.E7.AE.97.E7.AC.A6">内建的逗号表达式</a>,其中 <span class="t-c"><span class="mw-geshi cpp source-cpp">e</span></span> 是这些表达式之一。</li>
|
|
</ul>
|
|
<p>此生存期规则有下列例外:</p>
|
|
<ul>
|
|
<li><span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw1">return</span></span></span> 语句中绑定到函数返回值的临时量不被延续:它在返回表达式的末尾立即销毁。这种 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw1">return</span></span></span> 语句始终返回悬垂引用。</li>
|
|
<li>在函数调用中绑定到函数形参的临时量,存在到含这次函数调用的全表达式结尾为止:如果函数返回一个生命长于全表达式的引用,那么它将成为悬垂引用。</li>
|
|
</ul>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx11">
|
|
<td>
|
|
<ul>
|
|
<li>绑定到 new 表达式中所用的初始化器中的引用的临时量,存在到含有该 new 表达式的全表达式结尾为止,而非被初始化对象的存在期间。如果被初始化对象的声明长于全表达式,那么它的引用成员将成为悬垂引用。</li>
|
|
</ul>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx20">
|
|
<td>
|
|
<ul>
|
|
<li>绑定到用直接初始化语法(圆括号),而非列表初始化语法(花括号)初始化的聚合体的引用元素中的引用的临时量,存在直至含该初始化器的全表达式末尾为止。</li>
|
|
</ul>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">struct</span> A <span class="br0">{</span>
|
|
<span class="kw4">int</span><span class="sy3">&&</span> r<span class="sy4">;</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
A a1<span class="br0">{</span><span class="nu0">7</span><span class="br0">}</span><span class="sy4">;</span> <span class="co1">// OK:延续生存期</span>
|
|
A a2<span class="br0">(</span><span class="nu0">7</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 良构,但有悬垂引用</span></pre></div>
|
|
</div>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<p>总而言之,临时量的生存期不能以进一步“传递”来延续:从绑定了该临时量的引用或数据成员初始化的第二引用不影响临时量的生存期。</p>
|
|
<h3><span class="mw-headline" id=".E6.B3.A8.E8.A7.A3">注解</span></h3>
|
|
<p>仅在函数形参声明,函数返回类型声明,类成员声明,以及带 <code>extern</code> 说明符时,引用可以不与初始化器一同出现。</p>
|
|
<p>在 <a rel="nofollow" class="external text" href="https://wg21.cmeerw.net/cwg/issue1696">CWG 问题 1696</a> 的解决方案前,容许在构造函数<a href="cpp-language-initializer_list.html" class="mw-redirect">初始化器列表</a>中绑定临时量到引用成员,而临时量只持续到构造函数退出前,而非对象存在期间。这种初始化从 CWG 1696 开始非良构,不过许多编译器仍然支持它(值得注意的例外是 clang)。</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 <utility></span>
|
|
<span class="co2">#include <sstream></span>
|
|
<span class="kw1">struct</span> S <span class="br0">{</span>
|
|
<span class="kw4">int</span> mi<span class="sy4">;</span>
|
|
<span class="kw4">const</span> <a href="cpp-utility-pair.html"><span class="kw1096">std::<span class="me2">pair</span></span></a><span class="sy1"><</span><span class="kw4">int</span>,<span class="kw4">int</span><span class="sy1">></span><span class="sy3">&</span> mp<span class="sy4">;</span> <span class="co1">// 引用成员</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
|
|
<span class="kw4">void</span> foo<span class="br0">(</span><span class="kw4">int</span><span class="br0">)</span> <span class="br0">{</span><span class="br0">}</span>
|
|
|
|
<span class="kw1">struct</span> A <span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw1">struct</span> B <span class="sy4">:</span> A <span class="br0">{</span>
|
|
<span class="kw4">int</span> n<span class="sy4">;</span>
|
|
operator <span class="kw4">int</span><span class="sy3">&</span><span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span> <span class="kw1">return</span> n<span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
|
|
B bar<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span> <span class="kw1">return</span> B<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="br0">}</span>
|
|
|
|
<span class="co1">//int& bad_r; // 错误:没有初始化器</span>
|
|
<span class="kw4">extern</span> <span class="kw4">int</span><span class="sy3">&</span> ext_r<span class="sy4">;</span> <span class="co1">// OK</span>
|
|
|
|
<span class="kw4">int</span> main<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span>
|
|
<span class="co1">// 左值</span>
|
|
<span class="kw4">int</span> n <span class="sy1">=</span> <span class="nu0">1</span><span class="sy4">;</span>
|
|
<span class="kw4">int</span><span class="sy3">&</span> r1 <span class="sy1">=</span> n<span class="sy4">;</span> <span class="co1">// 到对象 n 的左值引用</span>
|
|
<span class="kw4">const</span> <span class="kw4">int</span><span class="sy3">&</span> cr<span class="br0">(</span>n<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 引用可以有更多 cv 限定</span>
|
|
<span class="kw4">volatile</span> <span class="kw4">int</span><span class="sy3">&</span> cv<span class="br0">{</span>n<span class="br0">}</span><span class="sy4">;</span> <span class="co1">// 可使用任何初始化器语法</span>
|
|
<span class="kw4">int</span><span class="sy3">&</span> r2 <span class="sy1">=</span> r1<span class="sy4">;</span> <span class="co1">// 另一到对象 n 的左值引用</span>
|
|
<span class="co1">// int& bad = cr; // 错误:更少 cv 限定</span>
|
|
<span class="kw4">int</span><span class="sy3">&</span> r3 <span class="sy1">=</span> <span class="kw1">const_cast</span><span class="sy1"><</span><span class="kw4">int</span><span class="sy3">&</span><span class="sy1">></span><span class="br0">(</span>cr<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 需要 const_cast</span>
|
|
|
|
<span class="kw4">void</span> <span class="br0">(</span><span class="sy3">&</span>rf<span class="br0">)</span><span class="br0">(</span><span class="kw4">int</span><span class="br0">)</span> <span class="sy1">=</span> foo<span class="sy4">;</span> <span class="co1">// 到函数的左值引用</span>
|
|
<span class="kw4">int</span> ar<span class="br0">[</span><span class="nu0">3</span><span class="br0">]</span><span class="sy4">;</span>
|
|
<span class="kw4">int</span> <span class="br0">(</span><span class="sy3">&</span>ra<span class="br0">)</span><span class="br0">[</span><span class="nu0">3</span><span class="br0">]</span> <span class="sy1">=</span> ar<span class="sy4">;</span> <span class="co1">// 到数组的左值引用</span>
|
|
|
|
B b<span class="sy4">;</span>
|
|
A<span class="sy3">&</span> base_ref <span class="sy1">=</span> b<span class="sy4">;</span> <span class="co1">// 到基类子对象的左值引用</span>
|
|
<span class="kw4">int</span><span class="sy3">&</span> converted_ref <span class="sy1">=</span> b<span class="sy4">;</span> <span class="co1">// 到转换结果的左值引用</span>
|
|
|
|
<span class="co1">// 右值</span>
|
|
<span class="co1">// int& bad = 1; // 错误:不能绑定左值引用到右值</span>
|
|
<span class="kw4">const</span> <span class="kw4">int</span><span class="sy3">&</span> cref <span class="sy1">=</span> <span class="nu0">1</span><span class="sy4">;</span> <span class="co1">// 绑定到右值</span>
|
|
<span class="kw4">int</span><span class="sy3">&&</span> rref <span class="sy1">=</span> <span class="nu0">1</span><span class="sy4">;</span> <span class="co1">// 绑定到右值</span>
|
|
|
|
<span class="kw4">const</span> A<span class="sy3">&</span> cref2 <span class="sy1">=</span> bar<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 到 B 临时量的 A 子对象的引用</span>
|
|
A<span class="sy3">&&</span> rref2 <span class="sy1">=</span> bar<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 相同</span>
|
|
|
|
<span class="kw4">int</span><span class="sy3">&&</span> xref <span class="sy1">=</span> <span class="kw1">static_cast</span><span class="sy1"><</span><span class="kw4">int</span><span class="sy3">&&</span><span class="sy1">></span><span class="br0">(</span>n<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 直接绑定到 n</span>
|
|
<span class="co1">// int&& copy_ref = n; // 错误:不能绑定到左值</span>
|
|
<span class="kw4">double</span><span class="sy3">&&</span> copy_ref <span class="sy1">=</span> n<span class="sy4">;</span> <span class="co1">// 绑定到值为 1.0 的右值临时量</span>
|
|
|
|
<span class="co1">// 临时量生存期上的限制</span>
|
|
<a href="cpp-io-basic_ostream.html"><span class="kw1729">std::<span class="me2">ostream</span></span></a><span class="sy3">&</span> buf_ref <span class="sy1">=</span> <a href="cpp-io-basic_ostringstream.html"><span class="kw1736">std::<span class="me2">ostringstream</span></span></a><span class="br0">(</span><span class="br0">)</span> <span class="sy1"><<</span> <span class="st0">'a'</span><span class="sy4">;</span> <span class="co1">// ostringstream 临时量</span>
|
|
<span class="co1">// 被绑定到 operator<< 的左运算数,但是它的生存期在分号结束,</span>
|
|
<span class="co1">// 所以 buf_ref 是悬垂引用。</span>
|
|
|
|
S a <span class="br0">{</span> <span class="nu0">1</span>, <span class="br0">{</span><span class="nu0">2</span>, <span class="nu0">3</span><span class="br0">}</span> <span class="br0">}</span><span class="sy4">;</span> <span class="co1">// 绑定临时量 pair {2,3} 到引用成员 a.mp 并延长其生存期以匹配 a</span>
|
|
S<span class="sy2">*</span> p <span class="sy1">=</span> new S<span class="br0">{</span> <span class="nu0">1</span>, <span class="br0">{</span><span class="nu0">2</span>, <span class="nu0">3</span><span class="br0">}</span> <span class="br0">}</span><span class="sy4">;</span> <span class="co1">// 绑定临时量 pair {2,3} 到引用成员 p->mp ,</span>
|
|
<span class="co1">// 但是它的生存期在分号结束</span>
|
|
<span class="co1">// p->mp 是悬垂引用</span>
|
|
delete p<span class="sy4">;</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
</div>
|
|
<h3><span class="mw-headline" id=".E7.BC.BA.E9.99.B7.E6.8A.A5.E5.91.8A">缺陷报告</span></h3>
|
|
<p>下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。</p>
|
|
<table class="dsctable" style="font-size:0.8em">
|
|
<tr>
|
|
<th>DR</th>
|
|
<th>应用于</th>
|
|
<th>出版时的行为</th>
|
|
<th>正确行为</th>
|
|
</tr>
|
|
<tr>
|
|
<td><a rel="nofollow" class="external text" href="https://wg21.cmeerw.net/cwg/issue1299">CWG 1299</a></td>
|
|
<td>C++98</td>
|
|
<td>临时量的定义不明确</td>
|
|
<td>使之明确</td>
|
|
</tr>
|
|
</table>
|
|
<h3><span class="mw-headline" id=".E5.8F.82.E9.98.85">参阅</span></h3>
|
|
<ul>
|
|
<li><a href="cpp-language-constructor.html">构造函数</a></li>
|
|
<li><a href="cpp-language-converting_constructor.html">转换构造函数</a></li>
|
|
<li><a href="cpp-language-copy_assignment.html">复制赋值</a></li>
|
|
<li><a href="cpp-language-copy_constructor.html">复制构造函数</a></li>
|
|
<li><a href="cpp-language-explicit.html">explicit</a></li>
|
|
<li><a href="cpp-language-initialization.html">初始化</a>
|
|
<ul>
|
|
<li><a href="cpp-language-constant_initialization.html">常量初始化</a></li>
|
|
<li><a href="cpp-language-copy_initialization.html">复制初始化</a></li>
|
|
<li><a href="cpp-language-direct_initialization.html">直接初始化</a></li>
|
|
<li><a href="cpp-language-list_initialization.html">列表初始化</a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a href="cpp-language-move_assignment.html">移动赋值</a></li>
|
|
<li><a href="cpp-language-move_constructor.html">移动构造函数</a></li>
|
|
<li><a href="cpp-language-new.html">new</a></li>
|
|
</ul>
|
|
</div>
|
|
<div class="visualClear"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|