219 lines
23 KiB
HTML
219 lines
23 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_default_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><span class="t-spar">T</span> <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>new</b></code> <span class="t-spar">T</span>
|
|
<p><code><b>new</b></code> <span class="t-spar">T</span> <code><b>(</b></code> <code><b>)</b></code> <span class="t-mark-rev t-until-cxx03">(C++03 前)</span></p>
|
|
</td>
|
|
<td>(2)</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>默认初始化在三种情况下进行:</p>
|
|
<div class="t-li1"><span class="t-li">1)</span> 当不带初始化器而声明具有自动、静态或线程局部<a href="cpp-language-storage_duration.html">存储期</a>的变量时;</div>
|
|
<div class="t-li1"><span class="t-li">2)</span> 当以不带初始化器的 <a href="cpp-language-new.html">new 表达式</a>创建具有动态存储期的对象时<span class="t-rev-inl t-until-cxx03"><span>,或当以带有由一个空括号对组成的初始化器的 new 表达式创建对象时</span> <span><span class="t-mark-rev t-until-cxx03">(C++03 前)</span></span></span>;</div>
|
|
<div class="t-li1"><span class="t-li">3)</span> 当<a href="cpp-language-constructor.html">构造函数初始化器列表</a>中未提及某个基类或非静态数据成员,且调用了该构造函数时。</div>
|
|
<p>默认初始化的效果是:</p>
|
|
<ul>
|
|
<li>如果 <code>T</code> 是<span class="t-rev-inl t-until-cxx11"><span>非 POD</span> <span><span class="t-mark-rev t-until-cxx11">(C++11 前)</span></span></span>类类型,那么考虑各构造函数并实施针对空实参列表的<a href="cpp-language-overload_resolution.html">重载决议</a>。调用所选的构造函数(即<a href="cpp-language-default_constructor.html">默认构造函数</a>之一),以提供新对象的初始值;</li>
|
|
<li>如果 <code>T</code> 是数组类型,那么该数组的每个元素都被默认初始化;</li>
|
|
<li>否则,不做任何事:具有自动存储期的对象(及其子对象)被初始化为不确定值。</li>
|
|
</ul>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-until-cxx11">
|
|
<td>
|
|
<p>只有具有自动存储期的(可有 cv 限定的)非 POD 类类型(或其数组)曾被认为在不使用初始化器时默认初始化。具有动态存储期的标量和 POD 类型曾被认为不被初始化(从 C++11 起,这种情况被重新分类为默认初始化的一种形式)。</p>
|
|
</td>
|
|
<td><span class="t-mark-rev t-until-cxx11">(C++11 前)</span></td>
|
|
</tr>
|
|
<tr class="t-rev t-until-cxx03">
|
|
<td>
|
|
<p>在(引入<a href="cpp-language-value_initialization.html">值初始化</a>的)C++03 前,表达式 <span class="t-c"><span class="mw-geshi cpp source-cpp">new T<span class="br0">(</span><span class="br0">)</span></span></span>,以及带一个空括号对形式的指名基类或成员的成员初始化器,曾被分类为默认初始化,但对非类类型则指定为<a href="cpp-language-zero_initialization.html">零初始化</a>。</p>
|
|
</td>
|
|
<td><span class="t-mark-rev t-until-cxx03">(C++03 前)</span></td>
|
|
</tr>
|
|
</table>
|
|
<p><br /></p>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-until-cxx11">
|
|
<td>
|
|
<p>如果 <code>T</code> 是有 cv 限定的类型,那么默认初始化会采用其无 cv 限定版本。</p>
|
|
</td>
|
|
<td><span class="t-mark-rev t-until-cxx11">(C++11 前)</span></td>
|
|
</tr>
|
|
</table>
|
|
<h4><span class="mw-headline" id="const_.E5.AF.B9.E8.B1.A1.E7.9A.84.E9.BB.98.E8.AE.A4.E5.88.9D.E5.A7.8B.E5.8C.96">const 对象的默认初始化</span></h4>
|
|
<p>如果程序调用有 <a href="cpp-language-cv.html">const</a> 限定类型的 <code>T</code> 对象的默认初始化,则 <code>T</code> 应当为 <i>const 可默认构造</i>类类型或其数组。</p>
|
|
<p>如果类类型 <code>T</code> 的默认初始化会调用用户提供<span class="t-rev-inl t-since-cxx11"><span>(不是从基类继承)</span> <span><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></span></span>的 <code>T</code> 构造函数,或满足以下条件,那么 <code>T</code> 为 const 可默认构造:</p>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-until-cxx11">
|
|
<td>
|
|
<ul>
|
|
<li><code>T</code> 的每个直接非静态数据成员 <code>M</code> 拥有类类型 <code>X</code> (或其数组), <code>X</code> 为 const 可默认构造,且</li>
|
|
<li><code>T</code> 没有直接<a href="cpp-language-union.html#.E8.81.94.E5.90.88.E4.BD.93.E5.BC.8F.E7.9A.84.E7.B1.BB">变体成员</a>,且</li>
|
|
</ul>
|
|
</td>
|
|
<td><span class="t-mark-rev t-until-cxx11">(C++11 前)</span></td>
|
|
</tr>
|
|
<tr class="t-rev t-since-cxx11">
|
|
<td>
|
|
<ul>
|
|
<li><code>T</code> 的每个直接非变体非静态数据成员 <code>M</code> 均拥有<a href="cpp-language-data_members.html#.E6.88.90.E5.91.98.E5.88.9D.E5.A7.8B.E5.8C.96">默认成员初始化器</a>,或如果 <code>M</code> 拥有类类型 <code>X</code> (或其数组), <code>X</code> 为 const 可默认构造,</li>
|
|
<li>如果 <code>T</code> 至少拥有一个非静态数据成员的联合体,刚好有一个<a href="cpp-language-union.html#.E8.81.94.E5.90.88.E4.BD.93.E5.BC.8F.E7.9A.84.E7.B1.BB">变体成员</a>拥有默认成员初始化器,</li>
|
|
<li>如果 <code>T</code> 不是联合体,那么对于每个至少拥有一个非静态数据成员的匿名联合体成员(若存在),刚好有一个非静态数据成员拥有默认成员初始化器,且</li>
|
|
</ul>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<p><code>T</code> 的每个潜在构造的基类均为 const 可默认构造。</p>
|
|
<h4><span class="mw-headline" id=".E4.BB.8E.E4.B8.8D.E7.A1.AE.E5.AE.9A.E5.AD.97.E8.8A.82.E8.AF.BB.E5.8F.96">从不确定字节读取</span></h4>
|
|
<p>使用由默认初始化任何非类类型的变量所取得的不确定的值是<a href="cpp-language-ub.html">未定义行为</a>(特别是,它可能是一种<a href="cpp-language-object.html#.E5.AF.B9.E8.B1.A1.E8.A1.A8.E7.A4.BA.E4.B8.8E.E5.80.BC.E8.A1.A8.E7.A4.BA">陷阱表示</a>),除了下列情况:</p>
|
|
<ul>
|
|
<li>将 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">unsigned</span> <span class="kw4">char</span></span></span> <span class="t-rev-inl t-since-cxx17"><span>或 <a href="cpp-types-byte.html"><tt>std::byte</tt></a></span> <span><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></span></span> 类型的不确定值赋值给另一拥有(可有 cv 限定的)<span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">unsigned</span> <span class="kw4">char</span></span></span> <span class="t-rev-inl t-since-cxx17"><span>或 <a href="cpp-types-byte.html"><tt>std::byte</tt></a></span> <span><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></span></span> 类型的变量(变量的值变为不确定,但该行为不是未定义);</li>
|
|
<li>用 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">unsigned</span> <span class="kw4">char</span></span></span> <span class="t-rev-inl t-since-cxx17"><span>或 <a href="cpp-types-byte.html"><tt>std::byte</tt></a></span> <span><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></span></span> 类型的不确定值初始化另一拥有(可有 cv 限定的)<span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">unsigned</span> <span class="kw4">char</span></span></span> <span class="t-rev-inl t-since-cxx17"><span>或 <a href="cpp-types-byte.html"><tt>std::byte</tt></a></span> <span><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></span></span>类型的变量;</li>
|
|
<li>从以下场合产生的 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">unsigned</span> <span class="kw4">char</span></span></span> <span class="t-rev-inl t-since-cxx17"><span>或 <a href="cpp-types-byte.html"><tt>std::byte</tt></a></span> <span><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></span></span> 类型的不确定值</li>
|
|
</ul>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>条件表达式的第二或第三操作数,</li>
|
|
<li>逗号运算符的右操作数,</li>
|
|
<li>转型或转换到(可有 cv 限定的)<span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">unsigned</span> <span class="kw4">char</span></span></span> <span class="t-rev-inl t-since-cxx17"><span>或 <a href="cpp-types-byte.html"><tt>std::byte</tt></a></span> <span><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></span></span>的操作数,</li>
|
|
<li>弃值表达式。</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">int</span> f<span class="br0">(</span><span class="kw4">bool</span> b<span class="br0">)</span>
|
|
<span class="br0">{</span>
|
|
<span class="kw4">int</span> x<span class="sy4">;</span> <span class="co1">// OK:x 的值不确定</span>
|
|
<span class="kw4">int</span> y <span class="sy1">=</span> x<span class="sy4">;</span> <span class="co1">// 未定义行为</span>
|
|
<span class="kw4">unsigned</span> <span class="kw4">char</span> c<span class="sy4">;</span> <span class="co1">// OK:c 的值不确定</span>
|
|
<span class="kw4">unsigned</span> <span class="kw4">char</span> d <span class="sy1">=</span> c<span class="sy4">;</span> <span class="co1">// OK:d 的值不确定</span>
|
|
<span class="kw4">int</span> e <span class="sy1">=</span> d<span class="sy4">;</span> <span class="co1">// 未定义行为</span>
|
|
<span class="kw1">return</span> b <span class="sy4">?</span> d <span class="sy4">:</span> <span class="nu0">0</span><span class="sy4">;</span> <span class="co1">// 如果 b 为 true 则行为未定义</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
<h3><span class="mw-headline" id=".E6.B3.A8.E8.A7.A3">注解</span></h3>
|
|
<p>具有自动和动态存储期的非类变量的默认初始化产生具有不确定值的对象(静态和线程局部对象进行的是<a href="cpp-language-zero_initialization.html">零初始化</a>)。</p>
|
|
<p>不能默认初始化引用和 const 标量对象。</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 <string></span>
|
|
|
|
<span class="kw1">struct</span> T1 <span class="br0">{</span> <span class="kw4">int</span> mem<span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span>
|
|
|
|
<span class="kw1">struct</span> T2
|
|
<span class="br0">{</span>
|
|
<span class="kw4">int</span> mem<span class="sy4">;</span>
|
|
T2<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span> <span class="br0">}</span> <span class="co1">// "mem" 不在初始化器列表中</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
|
|
<span class="kw4">int</span> n<span class="sy4">;</span> <span class="co1">// 静态非类,进行两阶段初始化:</span>
|
|
<span class="co1">// 1) 零初始化将 n 初始化为零</span>
|
|
<span class="co1">// 2) 默认初始化不做任何事,令 n 保留为零</span>
|
|
|
|
<span class="kw4">int</span> main<span class="br0">(</span><span class="br0">)</span>
|
|
<span class="br0">{</span>
|
|
<span class="kw4">int</span> n<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="sy4">;</span> <span class="co1">// 类,调用默认构造函数,值是 ""(空字符串)</span>
|
|
<a href="cpp-string-basic_string.html"><span class="kw1230">std::<span class="me2">string</span></span></a> a<span class="br0">[</span><span class="nu0">2</span><span class="br0">]</span><span class="sy4">;</span> <span class="co1">// 数组,默认初始化其各元素,值是 {"", ""}</span>
|
|
<span class="co1">// int& r; // 错误:引用</span>
|
|
<span class="co1">// const int n; // 错误:const 的非类</span>
|
|
<span class="co1">// const T1 t1; // 错误:const 的带隐式默认构造函数的类</span>
|
|
T1 t1<span class="sy4">;</span> <span class="co1">// 类,调用隐式默认构造函数</span>
|
|
<span class="kw4">const</span> T2 t2<span class="sy4">;</span> <span class="co1">// const 类,调用用户提供的默认构造函数</span>
|
|
<span class="co1">// t2.mem 被默认初始化(为不确定值)</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/issue253">CWG 253</a></td>
|
|
<td>C++98</td>
|
|
<td>const 对象的默认初始化不能调用隐式声明的默认构造函数</td>
|
|
<td>如果所有子对象已初始化则允许</td>
|
|
</tr>
|
|
<tr>
|
|
<td><a rel="nofollow" class="external text" href="https://wg21.cmeerw.net/cwg/issue616">CWG 616</a></td>
|
|
<td>C++98</td>
|
|
<td>任何未初始化对象的左值到右值的转换都是未定义行为</td>
|
|
<td>允许值不确定的 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">unsigned</span> <span class="kw4">char</span></span></span></td>
|
|
</tr>
|
|
<tr>
|
|
<td><a rel="nofollow" class="external text" href="https://wg21.cmeerw.net/cwg/issue1787">CWG 1787</a></td>
|
|
<td>C++98</td>
|
|
<td>从缓存于寄存器的不确定的 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">unsigned</span> <span class="kw4">char</span></span></span> 读取是未定义行为</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-converting_constructor.html">转换构造函数</a></li>
|
|
<li><a href="cpp-language-default_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-aggregate_initialization.html">聚合初始化</a></li>
|
|
<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>
|
|
<li><a href="cpp-language-reference_initialization.html">引用初始化</a></li>
|
|
<li><a href="cpp-language-value_initialization.html">值初始化</a></li>
|
|
<li><a href="cpp-language-zero_initialization.html">零初始化</a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a href="cpp-language-new.html">new</a></li>
|
|
</ul>
|
|
</div>
|
|
<div class="visualClear"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|