292 lines
36 KiB
HTML
292 lines
36 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 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>
|
|
<p>引用变量声明是<a href="cpp-language-declarations.html">声明符</a>拥有下列形式的简单声明:</p>
|
|
<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><span class="t-mark">(可选)</span> <span class="t-spar">声明符</span></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>&&</b></code> <span class="t-spar">属性</span><span class="t-mark">(可选)</span> <span class="t-spar">声明符</span></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>
|
|
</table>
|
|
<div class="t-li1"><span class="t-li">1)</span> <b>左值引用声明符</b>:声明 <span class="t-c"><span class="mw-geshi cpp source-cpp">S<span class="sy3">&</span> D<span class="sy4">;</span></span></span> 将 <code>D</code> 声明为到 <span class="t-spar">声明说明符序列</span> 所确定的类型 <code>S</code> 的<i>左值引用</i>。</div>
|
|
<div class="t-li1"><span class="t-li">2)</span> <b>右值引用声明符</b>:声明 <span class="t-c"><span class="mw-geshi cpp source-cpp">S<span class="sy3">&&</span> D<span class="sy4">;</span></span></span> 将 <code>D</code> 声明为到 <span class="t-spar">声明说明符序列</span> 所确定的类型 <code>S</code> 的<i>右值引用</i>。</div>
|
|
<table class="t-par-begin">
|
|
<tr class="t-par">
|
|
<td><span class="t-spar">声明符</span></td>
|
|
<td>-</td>
|
|
<td>除引用<a href="cpp-language-declarations.html">声明符</a>之外的任何其他声明符(不存在引用的引用)</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>
|
|
</table>
|
|
<p>引用必须被初始化为指代一个有效的对象或函数:见<a href="cpp-language-reference_initialization.html">引用初始化</a>。</p>
|
|
<p>不存在 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">void</span></span></span> 的引用,也不存在引用的引用。</p>
|
|
<p>引用类型无法在顶层被 <a href="cpp-language-cv.html">cv 限定</a>;声明中没有为此而设的语法,而如果添加限定性到 typedef 名、 <a href="cpp-language-decltype.html"><code>decltype</code></a> 说明符或<a href="cpp-language-template_parameters.html#.E7.B1.BB.E5.9E.8B.E6.A8.A1.E6.9D.BF.E5.BD.A2.E5.8F.82">类型模板形参</a>,则忽略它。</p>
|
|
<p>引用不是对象;它们不必占用存储,尽管编译器会在需要实现所需语义(例如,引用类型的非静态数据成员通常会增加类的大小,量为存储内存地址所需)的情况下分配存储。</p>
|
|
<p>因为引用不是对象,所以不存在引用的数组,不存在指向引用的指针,不存在引用的引用:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw4">int</span><span class="sy3">&</span> a<span class="br0">[</span><span class="nu0">3</span><span class="br0">]</span><span class="sy4">;</span> <span class="co1">// 错误</span>
|
|
<span class="kw4">int</span><span class="sy3">&</span><span class="sy2">*</span> p<span class="sy4">;</span> <span class="co1">// 错误</span>
|
|
<span class="kw4">int</span><span class="sy3">&</span> <span class="sy3">&</span>r<span class="sy4">;</span> <span class="co1">// 错误</span></pre></div>
|
|
</div>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx11">
|
|
<td>
|
|
<h5><span class="mw-headline" id=".E5.BC.95.E7.94.A8.E6.8A.98.E5.8F.A0">引用折叠</span></h5>
|
|
<p>通过模板或 typedef 中的类型操作可以构成引用的引用,此时适用<i>引用折叠(reference collapsing)</i>规则:右值引用的右值引用折叠成右值引用,所有其他组合均折叠成左值引用:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">typedef</span> <span class="kw4">int</span><span class="sy3">&</span> lref<span class="sy4">;</span>
|
|
<span class="kw1">typedef</span> <span class="kw4">int</span><span class="sy3">&&</span> rref<span class="sy4">;</span>
|
|
<span class="kw4">int</span> n<span class="sy4">;</span>
|
|
lref<span class="sy3">&</span> r1 <span class="sy1">=</span> n<span class="sy4">;</span> <span class="co1">// r1 的类型是 int&</span>
|
|
lref<span class="sy3">&&</span> r2 <span class="sy1">=</span> n<span class="sy4">;</span> <span class="co1">// r2 的类型是 int&</span>
|
|
rref<span class="sy3">&</span> r3 <span class="sy1">=</span> n<span class="sy4">;</span> <span class="co1">// r3 的类型是 int&</span>
|
|
rref<span class="sy3">&&</span> r4 <span class="sy1">=</span> <span class="nu0">1</span><span class="sy4">;</span> <span class="co1">// r4 的类型是 int&&</span></pre></div>
|
|
</div>
|
|
<p>(这条规则,和将 <code>T&&</code> 用于函数模板时的<a href="cpp-language-template_argument_deduction.html">模板实参推导</a>的特殊规则一起,组成了使得 <span class="t-lc"><a href="cpp-utility-forward.html">std::forward</a></span> 可行的规则。)</p>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<h4><span class="mw-headline" id=".E5.B7.A6.E5.80.BC.E5.BC.95.E7.94.A8">左值引用</span></h4>
|
|
<p>左值引用可用于建立既存对象的别名(可拥有不同的 cv 限定):</p>
|
|
<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="co2">#include <string></span>
|
|
|
|
<span class="kw4">int</span> main<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span>
|
|
<a href="cpp-string-basic_string.html"><span class="kw1230">std::<span class="me2">string</span></span></a> s <span class="sy1">=</span> <span class="st0">"Ex"</span><span class="sy4">;</span>
|
|
<a href="cpp-string-basic_string.html"><span class="kw1230">std::<span class="me2">string</span></span></a><span class="sy3">&</span> r1 <span class="sy1">=</span> s<span class="sy4">;</span>
|
|
<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> r2 <span class="sy1">=</span> s<span class="sy4">;</span>
|
|
|
|
r1 <span class="sy2">+</span><span class="sy1">=</span> <span class="st0">"ample"</span><span class="sy4">;</span> <span class="co1">// 修改 s</span>
|
|
<span class="co1">// r2 += "!"; // 错误:不能通过到 const 的引用修改</span>
|
|
<a href="cpp-io-cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1"><<</span> r2 <span class="sy1"><<</span> <span class="st0">'<span class="es1">\n</span>'</span><span class="sy4">;</span> <span class="co1">// 打印 s,它现在保有 "Example"</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
</div>
|
|
<p>它们也能用于在函数调用中实现按引用传递语义:</p>
|
|
<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="co2">#include <string></span>
|
|
|
|
<span class="kw4">void</span> double_string<span class="br0">(</span><a href="cpp-string-basic_string.html"><span class="kw1230">std::<span class="me2">string</span></span></a><span class="sy3">&</span> s<span class="br0">)</span> <span class="br0">{</span>
|
|
s <span class="sy2">+</span><span class="sy1">=</span> s<span class="sy4">;</span> <span class="co1">// 's' 与 main() 的 'str' 是同一对象</span>
|
|
<span class="br0">}</span>
|
|
|
|
<span class="kw4">int</span> main<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span>
|
|
<a href="cpp-string-basic_string.html"><span class="kw1230">std::<span class="me2">string</span></span></a> str <span class="sy1">=</span> <span class="st0">"Test"</span><span class="sy4">;</span>
|
|
double_string<span class="br0">(</span>str<span class="br0">)</span><span class="sy4">;</span>
|
|
<a href="cpp-io-cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1"><<</span> str <span class="sy1"><<</span> <span class="st0">'<span class="es1">\n</span>'</span><span class="sy4">;</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
</div>
|
|
<p>当函数的返回值是左值引用时,函数调用表达式成为<a href="cpp-language-value_category.html">左值表达式</a>:</p>
|
|
<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="co2">#include <string></span>
|
|
|
|
<span class="kw4">char</span><span class="sy3">&</span> char_number<span class="br0">(</span><a href="cpp-string-basic_string.html"><span class="kw1230">std::<span class="me2">string</span></span></a><span class="sy3">&</span> s, <a href="cpp-types-size_t.html"><span class="kw100">std::<span class="me2">size_t</span></span></a> n<span class="br0">)</span> <span class="br0">{</span>
|
|
<span class="kw1">return</span> s.<span class="me1">at</span><span class="br0">(</span>n<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// string::at() 返回 char 的引用</span>
|
|
<span class="br0">}</span>
|
|
|
|
<span class="kw4">int</span> main<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span>
|
|
<a href="cpp-string-basic_string.html"><span class="kw1230">std::<span class="me2">string</span></span></a> str <span class="sy1">=</span> <span class="st0">"Test"</span><span class="sy4">;</span>
|
|
char_number<span class="br0">(</span>str, <span class="nu0">1</span><span class="br0">)</span> <span class="sy1">=</span> <span class="st0">'a'</span><span class="sy4">;</span> <span class="co1">// 函数调用是左值,可被赋值</span>
|
|
<a href="cpp-io-cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1"><<</span> str <span class="sy1"><<</span> <span class="st0">'<span class="es1">\n</span>'</span><span class="sy4">;</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
</div>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx11">
|
|
<td>
|
|
<h4><span class="mw-headline" id=".E5.8F.B3.E5.80.BC.E5.BC.95.E7.94.A8">右值引用</span></h4>
|
|
<p>右值引用可用于为临时对象<a href="cpp-language-reference_initialization.html#.E4.B8.B4.E6.97.B6.E9.87.8F.E7.94.9F.E5.AD.98.E6.9C.9F">延长生存期</a>(注意,到 const 的左值引用也能延长临时对象生存期,但这些对象无法因此被修改):</p>
|
|
<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="co2">#include <string></span>
|
|
|
|
<span class="kw4">int</span> main<span class="br0">(</span><span class="br0">)</span>
|
|
<span class="br0">{</span>
|
|
<a href="cpp-string-basic_string.html"><span class="kw1230">std::<span class="me2">string</span></span></a> s1 <span class="sy1">=</span> <span class="st0">"Test"</span><span class="sy4">;</span>
|
|
<span class="co1">// std::string&& r1 = s1; // 错误:不能绑定到左值</span>
|
|
|
|
<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> r2 <span class="sy1">=</span> s1 <span class="sy2">+</span> s1<span class="sy4">;</span> <span class="co1">// okay:到 const 的左值引用延长生存期</span>
|
|
<span class="co1">// r2 += "Test"; // 错误:不能通过到 const 的引用修改</span>
|
|
|
|
<a href="cpp-string-basic_string.html"><span class="kw1230">std::<span class="me2">string</span></span></a><span class="sy3">&&</span> r3 <span class="sy1">=</span> s1 <span class="sy2">+</span> s1<span class="sy4">;</span> <span class="co1">// okay:右值引用延长生存期</span>
|
|
r3 <span class="sy2">+</span><span class="sy1">=</span> <span class="st0">"Test"</span><span class="sy4">;</span> <span class="co1">// okay:能通过到非 const 的引用修改</span>
|
|
<a href="cpp-io-cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1"><<</span> r3 <span class="sy1"><<</span> <span class="st0">'<span class="es1">\n</span>'</span><span class="sy4">;</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
</div>
|
|
<p>更重要的是,当函数同时具有右值引用和左值引用的<a href="cpp-language-overload_resolution.html">重载</a>时,右值引用重载绑定到右值(包含纯右值和亡值),而左值引用重载绑定到左值:</p>
|
|
<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="co2">#include <utility></span>
|
|
|
|
<span class="kw4">void</span> f<span class="br0">(</span><span class="kw4">int</span><span class="sy3">&</span> x<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">"左值引用重载 f("</span> <span class="sy1"><<</span> x <span class="sy1"><<</span> <span class="st0">")<span class="es1">\n</span>"</span><span class="sy4">;</span>
|
|
<span class="br0">}</span>
|
|
|
|
<span class="kw4">void</span> f<span class="br0">(</span><span class="kw4">const</span> <span class="kw4">int</span><span class="sy3">&</span> x<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">"到 const 的左值引用重载 f("</span> <span class="sy1"><<</span> x <span class="sy1"><<</span> <span class="st0">")<span class="es1">\n</span>"</span><span class="sy4">;</span>
|
|
<span class="br0">}</span>
|
|
|
|
<span class="kw4">void</span> f<span class="br0">(</span><span class="kw4">int</span><span class="sy3">&&</span> x<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">"右值引用重载 f("</span> <span class="sy1"><<</span> x <span class="sy1"><<</span> <span class="st0">")<span class="es1">\n</span>"</span><span class="sy4">;</span>
|
|
<span class="br0">}</span>
|
|
|
|
<span class="kw4">int</span> main<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span>
|
|
<span class="kw4">int</span> i <span class="sy1">=</span> <span class="nu0">1</span><span class="sy4">;</span>
|
|
<span class="kw4">const</span> <span class="kw4">int</span> ci <span class="sy1">=</span> <span class="nu0">2</span><span class="sy4">;</span>
|
|
f<span class="br0">(</span>i<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 调用 f(int&)</span>
|
|
f<span class="br0">(</span>ci<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 调用 f(const int&)</span>
|
|
f<span class="br0">(</span><span class="nu0">3</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 调用 f(int&&),如果没有 f(int&&) 重载则会调用 f(const int&)</span>
|
|
f<span class="br0">(</span>std<span class="sy4">::</span><span class="me2">move</span><span class="br0">(</span>i<span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 调用 f(int&&)</span>
|
|
|
|
<span class="co1">// 右值引用变量在用于表达式时是左值</span>
|
|
<span class="kw4">int</span><span class="sy3">&&</span> x <span class="sy1">=</span> <span class="nu0">1</span><span class="sy4">;</span>
|
|
f<span class="br0">(</span>x<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 调用 f(int& x)</span>
|
|
f<span class="br0">(</span>std<span class="sy4">::</span><span class="me2">move</span><span class="br0">(</span>x<span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 调用 f(int&& x)</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
</div>
|
|
<p>这允许在适当时机自动选择<a href="cpp-language-move_constructor.html">移动构造函数</a>、<a href="cpp-language-move_assignment.html">移动赋值</a>运算符和其他具有移动能力的函数(例如 <span class="t-lc"><a href="cpp-container-vector-push_back.html">std::vector::push_back()</a></span>)。</p>
|
|
<p>因为右值引用能绑定到亡值,所以它们能指代非临时对象:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><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> std<span class="sy4">::</span><span class="me2">move</span><span class="br0">(</span>i2<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 直接绑定到 i2</span></pre></div>
|
|
</div>
|
|
<p>这使得作用域中不再需要的对象可以被移动出去:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><a href="cpp-container-vector.html"><span class="kw1269">std::<span class="me2">vector</span></span></a><span class="sy1"><</span><span class="kw4">int</span><span class="sy1">></span> v<span class="br0">{</span><span class="nu0">1</span>,<span class="nu0">2</span>,<span class="nu0">3</span>,<span class="nu0">4</span>,<span class="nu0">5</span><span class="br0">}</span><span class="sy4">;</span>
|
|
<a href="cpp-container-vector.html"><span class="kw1269">std::<span class="me2">vector</span></span></a><span class="sy1"><</span><span class="kw4">int</span><span class="sy1">></span> v2<span class="br0">(</span>std<span class="sy4">::</span><span class="me2">move</span><span class="br0">(</span>v<span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 绑定右值引用到 v</span>
|
|
<a href="cpp-error-assert.html"><span class="kw774">assert</span></a><span class="br0">(</span>v.<span class="me1">empty</span><span class="br0">(</span><span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span></pre></div>
|
|
</div>
|
|
</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-cxx11">
|
|
<td>
|
|
<h4><span class="mw-headline" id=".E8.BD.AC.E5.8F.91.E5.BC.95.E7.94.A8">转发引用</span></h4>
|
|
<p>转发引用是一种特殊的引用,它保持函数实参的值类别,使得 <span class="t-lc"><a href="cpp-utility-forward.html">std::forward</a></span> 能用来<i>转发</i>实参。转发引用是下列之一:</p>
|
|
<div class="t-li1"><span class="t-li">1)</span> 函数模板的函数形参,其被声明为同一函数模板的<a href="cpp-language-template_parameters.html#.E7.B1.BB.E5.9E.8B.E6.A8.A1.E6.9D.BF.E5.BD.A2.E5.8F.82">类型模板形参</a>的无 cv 限定的右值引用:
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">template</span><span class="sy1"><</span><span class="kw1">class</span> T<span class="sy1">></span>
|
|
<span class="kw4">int</span> f<span class="br0">(</span>T<span class="sy3">&&</span> x<span class="br0">)</span> <span class="br0">{</span> <span class="co1">// x 是转发引用</span>
|
|
<span class="kw1">return</span> g<span class="br0">(</span><a href="cpp-utility-forward.html"><span class="kw1117">std::<span class="me2">forward</span></span></a><span class="sy1"><</span>T<span class="sy1">></span><span class="br0">(</span>x<span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 从而能被转发</span>
|
|
<span class="br0">}</span>
|
|
<span class="kw4">int</span> main<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span>
|
|
<span class="kw4">int</span> i<span class="sy4">;</span>
|
|
f<span class="br0">(</span>i<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 实参是左值,调用 f<int&>(int&), std::forward<int&>(x) 是左值</span>
|
|
f<span class="br0">(</span><span class="nu0">0</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 实参是右值,调用 f<int>(int&&), std::forward<int>(x) 是右值</span>
|
|
<span class="br0">}</span>
|
|
|
|
<span class="kw1">template</span><span class="sy1"><</span><span class="kw1">class</span> T<span class="sy1">></span>
|
|
<span class="kw4">int</span> g<span class="br0">(</span><span class="kw4">const</span> T<span class="sy3">&&</span> x<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// x 不是转发引用:const T 不是无 cv 限定的</span>
|
|
|
|
<span class="kw1">template</span><span class="sy1"><</span><span class="kw1">class</span> T<span class="sy1">></span> <span class="kw1">struct</span> A <span class="br0">{</span>
|
|
<span class="kw1">template</span><span class="sy1"><</span><span class="kw1">class</span> U<span class="sy1">></span>
|
|
A<span class="br0">(</span>T<span class="sy3">&&</span> x, U<span class="sy3">&&</span> y, <span class="kw4">int</span><span class="sy2">*</span> p<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// x 不是转发引用:T 不是构造函数的类型模板形参</span>
|
|
<span class="co1">// 但 y 是转发引用</span>
|
|
<span class="br0">}</span><span class="sy4">;</span></pre></div>
|
|
</div>
|
|
</div>
|
|
<div class="t-li1"><span class="t-li">2)</span> <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">auto</span><span class="sy3">&&</span></span></span>,但当其从花括号包围的初始化器列表推导时除外:</div>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw4">auto</span><span class="sy3">&&</span> vec <span class="sy1">=</span> foo<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// foo() 可以是左值或右值,vec 是转发引用</span>
|
|
<span class="kw4">auto</span> i <span class="sy1">=</span> <a href="cpp-iterator-begin.html"><span class="kw676">std::<span class="me2">begin</span></span></a><span class="br0">(</span>vec<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 也可以</span>
|
|
<span class="br0">(</span><span class="sy2">*</span>i<span class="br0">)</span><span class="sy2">++</span><span class="sy4">;</span> <span class="co1">// 也可以</span>
|
|
g<span class="br0">(</span><a href="cpp-utility-forward.html"><span class="kw1117">std::<span class="me2">forward</span></span></a><span class="sy1"><</span>decltype<span class="br0">(</span>vec<span class="br0">)</span><span class="sy1">></span><span class="br0">(</span>vec<span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 转发,保持值类别</span>
|
|
|
|
<span class="kw1">for</span> <span class="br0">(</span><span class="kw4">auto</span><span class="sy3">&&</span> x<span class="sy4">:</span> f<span class="br0">(</span><span class="br0">)</span><span class="br0">)</span> <span class="br0">{</span>
|
|
<span class="co1">// x 是转发引用;这是使用范围 for 循环最安全的方式</span>
|
|
<span class="br0">}</span>
|
|
|
|
<span class="kw4">auto</span><span class="sy3">&&</span> z <span class="sy1">=</span> <span class="br0">{</span><span class="nu0">1</span>, <span class="nu0">2</span>, <span class="nu0">3</span><span class="br0">}</span><span class="sy4">;</span> <span class="co1">// *不是*转发引用(初始化器列表的特殊情形)</span></pre></div>
|
|
</div>
|
|
<p>参阅<a href="cpp-language-template_argument_deduction.html#.E4.BB.8E.E5.87.BD.E6.95.B0.E8.B0.83.E7.94.A8.E6.8E.A8.E5.AF.BC">模板实参推导</a>和 <span class="t-lc"><a href="cpp-utility-forward.html">std::forward</a></span>。</p>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<h4><span class="mw-headline" id=".E6.82.AC.E5.9E.82.E5.BC.95.E7.94.A8">悬垂引用</span></h4>
|
|
<p>尽管引用一旦初始化就始终指代一个有效的对象或函数,但有可能创建一个程序,其中被指代对象的<a href="cpp-language-lifetime.html">生存期</a>结束而引用仍保持可访问(<i>悬垂(dangling)</i>)。访问这种引用是未定义行为。 一个常见例子是返回自动变量的引用的函数:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><a href="cpp-string-basic_string.html"><span class="kw1230">std::<span class="me2">string</span></span></a><span class="sy3">&</span> f<span class="br0">(</span><span class="br0">)</span>
|
|
<span class="br0">{</span>
|
|
<a href="cpp-string-basic_string.html"><span class="kw1230">std::<span class="me2">string</span></span></a> s <span class="sy1">=</span> <span class="st0">"Example"</span><span class="sy4">;</span>
|
|
<span class="kw1">return</span> s<span class="sy4">;</span> <span class="co1">// 退出 s 的作用域:调用其析构函数并解分配其存储</span>
|
|
<span class="br0">}</span>
|
|
|
|
<a href="cpp-string-basic_string.html"><span class="kw1230">std::<span class="me2">string</span></span></a><span class="sy3">&</span> r <span class="sy1">=</span> f<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 悬垂引用</span>
|
|
<a href="cpp-io-cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1"><<</span> r<span class="sy4">;</span> <span class="co1">// 未定义行为:从悬垂引用读取</span>
|
|
<a href="cpp-string-basic_string.html"><span class="kw1230">std::<span class="me2">string</span></span></a> s <span class="sy1">=</span> f<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 未定义行为:从悬垂引用复制初始化</span></pre></div>
|
|
</div>
|
|
<p>注意,右值引用和到 const 的左值引用能延长临时对象的生存期(参阅<a href="cpp-language-reference_initialization.html#.E4.B8.B4.E6.97.B6.E9.87.8F.E7.94.9F.E5.AD.98.E6.9C.9F">引用初始化</a>中的规则和例外情况)。</p>
|
|
<p>如果被指代对象被销毁(例如通过显式的析构函数调用),但存储尚未被解分配,则到生存期外的对象的引用仍能以有限的方式使用,且当在同一存储中重新创建对象时也可以变为有效(细节见<a href="cpp-language-lifetime.html#.E5.9C.A8.E7.94.9F.E5.AD.98.E6.9C.9F.E4.B9.8B.E5.A4.96.E8.BF.9B.E8.A1.8C.E8.AE.BF.E9.97.AE">在生存期之外进行访问</a>)。</p>
|
|
</div>
|
|
<div class="visualClear"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|