167 lines
20 KiB
HTML
167 lines
20 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>std::launder</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_utility_launder skin-cppreference2 action-view cpp-navbar">
|
|
<div id="cpp-content-base">
|
|
<div id="content"><a id="top"></a>
|
|
<h1 id="firstHeading" class="firstHeading"><span style="font-size:0.7em; line-height:130%">std::</span>launder</h1>
|
|
<div id="bodyContent">
|
|
<div id="contentSub"><span class="subpages">< <a href="cpp.html">cpp</a>‎ | <a href="cpp-utility.html">utility</a></span></div>
|
|
<div id="mw-content-text" lang="zh" dir="ltr" class="mw-content-ltr" xml:lang="zh">
|
|
<table class="t-dcl-begin">
|
|
<tbody>
|
|
<tr class="t-dsc-header">
|
|
<td>
|
|
<div>定义于头文件 <code><a href="cpp-header-new.html"><new></a></code></div>
|
|
</td>
|
|
<td></td>
|
|
<td></td>
|
|
</tr>
|
|
</tbody>
|
|
<tbody class="t-dcl-rev">
|
|
<tr class="t-dcl t-since-cxx17 t-until-cxx20">
|
|
<td>
|
|
<div><span class="mw-geshi cpp source-cpp"><span class="kw1">template</span> <span class="sy1"><</span><span class="kw1">class</span> T<span class="sy1">></span><br />
|
|
<span class="kw4">constexpr</span> T<span class="sy2">*</span> launder<span class="br0">(</span>T<span class="sy2">*</span> p<span class="br0">)</span> <span class="kw1">noexcept</span><span class="sy4">;</span></span></div>
|
|
</td>
|
|
<td class="t-dcl-nopad"></td>
|
|
<td><span class="t-mark-rev t-since-cxx17">(C++17 起)</span><br />
|
|
<span class="t-mark-rev t-until-cxx20">(C++20 前)</span></td>
|
|
</tr>
|
|
<tr class="t-dcl t-since-cxx20">
|
|
<td>
|
|
<div><span class="mw-geshi cpp source-cpp"><span class="kw1">template</span> <span class="sy1"><</span><span class="kw1">class</span> T<span class="sy1">></span><br />
|
|
<span class="br0">[</span><span class="br0">[</span>nodiscard<span class="br0">]</span><span class="br0">]</span> <span class="kw4">constexpr</span> T<span class="sy2">*</span> launder<span class="br0">(</span>T<span class="sy2">*</span> p<span class="br0">)</span> <span class="kw1">noexcept</span><span class="sy4">;</span></span></div>
|
|
</td>
|
|
<td class="t-dcl-nopad"></td>
|
|
<td><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></td>
|
|
</tr>
|
|
</tbody>
|
|
<tbody>
|
|
<tr class="t-dcl-sep">
|
|
<td></td>
|
|
<td></td>
|
|
<td></td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<p>获得指向位于 <code>p</code> 所表示地址的对象的指针。</p>
|
|
<p>正式而言,给定</p>
|
|
<ul>
|
|
<li>表示内存中一个字节的地址 <code>A</code> 的指针 <code>p</code></li>
|
|
<li>一个位于地址 <code>A</code> 的对象 <code>X</code></li>
|
|
<li><code>X</code> 在其<a href="cpp-language-lifetime.html">生存期</a>内</li>
|
|
<li><code>X</code> 的类型与 <code>T</code> 相同,忽略每层的 cv 限定符</li>
|
|
<li>能通过结果触及的每个字节都能通过 p 触及(若字节在与 <code>Y</code> <a href="cpp-language-static_cast.html#.E6.8C.87.E9.92.88.E5.8F.AF.E4.BA.92.E8.BD.AC.E6.8D.A2">指针可互转换</a>的对象 <code>Z</code> 的存储内,或在以 <code>Z</code> 为元素的立即外围数组内,则能通过指向对象 <code>Y</code> 的指针触及这些字节)。</li>
|
|
</ul>
|
|
<p>则 <span class="t-c"><span class="mw-geshi cpp source-cpp">std<span class="sy4">::</span><span class="me2">launder</span><span class="br0">(</span>p<span class="br0">)</span></span></span> 返回 <code>T*</code> 类型的值,它指向对象 <code>X</code> 。否则行为未定义。</p>
|
|
<p>若 <code>T</code> 是函数类型或(可有 cv 限定的) <code>void</code> 则程序为谬构。</p>
|
|
<p><code>std::launder</code> 可用于<a href="cpp-language-constant_expression.html">核心常量表达式</a>,当且仅当其(转换后的)参数的值在函数调用的位置可使用。换言之, <code>std::launder</code> 不放松常量求值中的限制。</p>
|
|
<h3><span class="mw-headline" id=".E6.B3.A8.E8.A7.A3">注解</span></h3>
|
|
<p><code>std::launder</code> 在其参数上无效果。必须用其返回值访问对象。从而,舍弃返回值始终是错误。</p>
|
|
<p><code>std::launder</code> 的典型用途包括:</p>
|
|
<ul>
|
|
<li>获得指向在同类型既存对象的存储中创建的对象的指针,这里不能<a href="cpp-language-lifetime.html#.E5.AD.98.E5.82.A8.E7.9A.84.E9.87.8D.E7.94.A8">重用</a>指向旧对象的指针(例如,因为任一对象为基类子对象);</li>
|
|
<li>获得指向对象的指针,该对象由布置 <code>new</code> 从指向为该对象提供存储的对象的指针创建。</li>
|
|
</ul>
|
|
<p><i>可触及性</i>限制确保不能用 <code>std::launder</code> 访问不可通过原指针访问的字节,从而干涉编译器的逃逸分析。</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw4">int</span> x<span class="br0">[</span><span class="nu0">10</span><span class="br0">]</span><span class="sy4">;</span>
|
|
<span class="kw4">auto</span> p <span class="sy1">=</span> std<span class="sy4">::</span><span class="me2">launder</span><span class="br0">(</span><span class="kw1">reinterpret_cast</span><span class="sy1"><</span><span class="kw4">int</span><span class="br0">(</span><span class="sy2">*</span><span class="br0">)</span><span class="br0">[</span><span class="nu0">10</span><span class="br0">]</span><span class="sy1">></span><span class="br0">(</span><span class="sy3">&</span>x<span class="br0">[</span><span class="nu0">0</span><span class="br0">]</span><span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// OK</span>
|
|
|
|
<span class="kw4">int</span> x2<span class="br0">[</span><span class="nu0">2</span><span class="br0">]</span><span class="br0">[</span><span class="nu0">10</span><span class="br0">]</span><span class="sy4">;</span>
|
|
<span class="kw4">auto</span> p2 <span class="sy1">=</span> std<span class="sy4">::</span><span class="me2">launder</span><span class="br0">(</span><span class="kw1">reinterpret_cast</span><span class="sy1"><</span><span class="kw4">int</span><span class="br0">(</span><span class="sy2">*</span><span class="br0">)</span><span class="br0">[</span><span class="nu0">10</span><span class="br0">]</span><span class="sy1">></span><span class="br0">(</span><span class="sy3">&</span>x2<span class="br0">[</span><span class="nu0">0</span><span class="br0">]</span><span class="br0">[</span><span class="nu0">0</span><span class="br0">]</span><span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="co1">// 未定义行为:可通过产生的指向 x2[0] 的指针触及 x2[1] ,但不可从源触及</span>
|
|
|
|
<span class="kw1">struct</span> X <span class="br0">{</span> <span class="kw4">int</span> a<span class="br0">[</span><span class="nu0">10</span><span class="br0">]</span><span class="sy4">;</span> <span class="br0">}</span> x3, x4<span class="br0">[</span><span class="nu0">2</span><span class="br0">]</span><span class="sy4">;</span> <span class="co1">// 标准布局;假定无填充</span>
|
|
<span class="kw4">auto</span> p3 <span class="sy1">=</span> std<span class="sy4">::</span><span class="me2">launder</span><span class="br0">(</span><span class="kw1">reinterpret_cast</span><span class="sy1"><</span><span class="kw4">int</span><span class="br0">(</span><span class="sy2">*</span><span class="br0">)</span><span class="br0">[</span><span class="nu0">10</span><span class="br0">]</span><span class="sy1">></span><span class="br0">(</span><span class="sy3">&</span>x3.<span class="me1">a</span><span class="br0">[</span><span class="nu0">0</span><span class="br0">]</span><span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// OK</span>
|
|
<span class="kw4">auto</span> p4 <span class="sy1">=</span> std<span class="sy4">::</span><span class="me2">launder</span><span class="br0">(</span><span class="kw1">reinterpret_cast</span><span class="sy1"><</span><span class="kw4">int</span><span class="br0">(</span><span class="sy2">*</span><span class="br0">)</span><span class="br0">[</span><span class="nu0">10</span><span class="br0">]</span><span class="sy1">></span><span class="br0">(</span><span class="sy3">&</span>x4<span class="br0">[</span><span class="nu0">0</span><span class="br0">]</span>.<span class="me1">a</span><span class="br0">[</span><span class="nu0">0</span><span class="br0">]</span><span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="co1">// 未定义行为:可通过产生的指向 x4[0].a 的指针(它与 x4[0] 指针间可转换)触及 x4[1] ,但不可从源触及</span>
|
|
|
|
<span class="kw1">struct</span> Y <span class="br0">{</span> <span class="kw4">int</span> a<span class="br0">[</span><span class="nu0">10</span><span class="br0">]</span><span class="sy4">;</span> <span class="kw4">double</span> y<span class="sy4">;</span> <span class="br0">}</span> x5<span class="sy4">;</span>
|
|
<span class="kw4">auto</span> p5 <span class="sy1">=</span> std<span class="sy4">::</span><span class="me2">launder</span><span class="br0">(</span><span class="kw1">reinterpret_cast</span><span class="sy1"><</span><span class="kw4">int</span><span class="br0">(</span><span class="sy2">*</span><span class="br0">)</span><span class="br0">[</span><span class="nu0">10</span><span class="br0">]</span><span class="sy1">></span><span class="br0">(</span><span class="sy3">&</span>x5.<span class="me1">a</span><span class="br0">[</span><span class="nu0">0</span><span class="br0">]</span><span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="co1">// 未定义行为:可通过产生的指向 x5.a 的指针触及 x5.y ,但不可从源触及</span></pre></div>
|
|
</div>
|
|
<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 <new></span>
|
|
<span class="co2">#include <cstddef></span>
|
|
<span class="co2">#include <cassert></span>
|
|
|
|
<span class="kw1">struct</span> Y <span class="br0">{</span>
|
|
<span class="kw4">int</span> z<span class="sy4">;</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
|
|
<span class="kw1">struct</span> A <span class="br0">{</span>
|
|
<span class="kw1">virtual</span> <span class="kw4">int</span> transmogrify<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</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> transmogrify<span class="br0">(</span><span class="br0">)</span> override <span class="br0">{</span> new<span class="br0">(</span>this<span class="br0">)</span> A<span class="sy4">;</span> <span class="kw1">return</span> <span class="nu0">2</span><span class="sy4">;</span> <span class="br0">}</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
|
|
<span class="kw4">int</span> A<span class="sy4">::</span><span class="me2">transmogrify</span><span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span> new<span class="br0">(</span>this<span class="br0">)</span> B<span class="sy4">;</span> <span class="kw1">return</span> <span class="nu0">1</span><span class="sy4">;</span> <span class="br0">}</span>
|
|
|
|
static_assert<span class="br0">(</span>sizeof<span class="br0">(</span>B<span class="br0">)</span> <span class="sy1">==</span> sizeof<span class="br0">(</span>A<span class="br0">)</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>
|
|
<span class="co1">// 情况 1 :新对象无法为透明可替换,因为它是基类子对象而旧对象是完整对象。</span>
|
|
A i<span class="sy4">;</span>
|
|
<span class="kw4">int</span> n <span class="sy1">=</span> i.<span class="me1">transmogrify</span><span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="co1">// int m = i.transmogrify(); // 未定义行为</span>
|
|
<span class="kw4">int</span> m <span class="sy1">=</span> std<span class="sy4">::</span><span class="me2">launder</span><span class="br0">(</span><span class="sy3">&</span>i<span class="br0">)</span><span class="sy2">-</span><span class="sy1">></span>transmogrify<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// OK</span>
|
|
<a href="cpp-error-assert.html"><span class="kw774">assert</span></a><span class="br0">(</span>m <span class="sy2">+</span> n <span class="sy1">==</span> <span class="nu0">3</span><span class="br0">)</span><span class="sy4">;</span>
|
|
|
|
<span class="co1">// 情况 2 :通过指向字节数组的指针访问存储为该数组所提供的新对象。</span>
|
|
alignas<span class="br0">(</span>Y<span class="br0">)</span> std<span class="sy4">::</span><span class="me2">byte</span> s<span class="br0">[</span>sizeof<span class="br0">(</span>Y<span class="br0">)</span><span class="br0">]</span><span class="sy4">;</span>
|
|
Y<span class="sy2">*</span> q <span class="sy1">=</span> new<span class="br0">(</span><span class="sy3">&</span>s<span class="br0">)</span> Y<span class="br0">{</span><span class="nu0">2</span><span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw4">const</span> <span class="kw4">int</span> f <span class="sy1">=</span> <span class="kw1">reinterpret_cast</span><span class="sy1"><</span>Y<span class="sy2">*</span><span class="sy1">></span><span class="br0">(</span><span class="sy3">&</span>s<span class="br0">)</span><span class="sy2">-</span><span class="sy1">></span>z<span class="sy4">;</span> <span class="co1">// 类成员访问为未定义行为:</span>
|
|
<span class="co1">// reinterpret_cast<Y*>(&s) 拥有值</span>
|
|
<span class="co1">// “指向 s 的指针”而不指向 Y 对象</span>
|
|
<span class="kw4">const</span> <span class="kw4">int</span> g <span class="sy1">=</span> q<span class="sy2">-</span><span class="sy1">></span>z<span class="sy4">;</span> <span class="co1">// OK</span>
|
|
<span class="kw4">const</span> <span class="kw4">int</span> h <span class="sy1">=</span> std<span class="sy4">::</span><span class="me2">launder</span><span class="br0">(</span><span class="kw1">reinterpret_cast</span><span class="sy1"><</span>Y<span class="sy2">*</span><span class="sy1">></span><span class="br0">(</span><span class="sy3">&</span>s<span class="br0">)</span><span class="br0">)</span><span class="sy2">-</span><span class="sy1">></span>z<span class="sy4">;</span> <span class="co1">// OK</span>
|
|
|
|
<span class="br0">[</span>f, g, h<span class="br0">]</span> <span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span> <span class="co1">// 压制“未使用变量”警告;参阅 [[maybe_unused]] 。</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://cplusplus.github.io/LWG/issue2859">LWG 2859</a></td>
|
|
<td>C++17</td>
|
|
<td><i>可触及</i>的定义未考虑来自指针可互转换的对象的指针算术</td>
|
|
<td>已考虑</td>
|
|
</tr>
|
|
<tr>
|
|
<td><a rel="nofollow" class="external text" href="https://cplusplus.github.io/LWG/issue3495">LWG 3495</a></td>
|
|
<td>C++17</td>
|
|
<td><code>launder</code> 可以在常量表达式中令指向不活跃成员的指针可解引用</td>
|
|
<td>已禁止</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
<div class="visualClear"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|