257 lines
28 KiB
HTML
257 lines
28 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>值初始化(C++03 起)</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_value_initialization skin-cppreference2 action-view cpp-navbar">
|
|
<div id="cpp-content-base">
|
|
<div id="content"><a id="top"></a>
|
|
<h1 id="firstHeading" class="firstHeading">值初始化<span class="t-mark-rev t-since-cxx03">(C++03 起)</span></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><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> <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><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> <span class="t-spar">成员</span><code><b>()</b></code> <code><b>{</b></code> <span class="t-spar">...</span> <code><b>}</b></code></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> <span class="t-spar">对象</span> <code><b>{};</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">T</span><code><b>{}</b></code></td>
|
|
<td>(5)</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><code><b>new</b></code> <span class="t-spar">T</span> <code><b>{}</b></code></td>
|
|
<td>(6)</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><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> <span class="t-spar">成员</span><code><b>{}</b></code> <code><b>{</b></code> <span class="t-spar">...</span> <code><b>}</b></code></td>
|
|
<td>(7)</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>
|
|
<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,5)</span> 当以空的括号<span class="t-rev-inl t-since-cxx11"><span>或花括号</span> <span><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></span></span>对组成的初始化器创建无名临时对象时;</div>
|
|
<div class="t-li1"><span class="t-li">2,6)</span> 当 <a href="cpp-language-new.html">new 表达式</a>以空的括号<span class="t-rev-inl t-since-cxx11"><span>或花括号</span> <span><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></span></span>对组成的初始化器创建具有动态存储期的对象时;</div>
|
|
<div class="t-li1"><span class="t-li">3,7)</span> 当使用以空的括号<span class="t-rev-inl t-since-cxx11"><span>或花括号</span> <span><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></span></span>对组成的<a href="cpp-language-initializer_list.html" class="mw-redirect">成员初始化器</a>初始化非静态数据成员或基类时;</div>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx11">
|
|
<td>
|
|
<div class="t-li1"><span class="t-li">4)</span> 当以由空花括号对组成的初始化器声明具名对象(自动、静态或线程局部)时。</div>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<p>所有情况下,如果使用空花括号对 <code>{}</code> 且 <code>T</code> 是<i>聚合类型</i>,则进行<a href="cpp-language-aggregate_initialization.html">聚合初始化</a>而非值初始化。</p>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx11">
|
|
<td>
|
|
<p>如果 <code>T</code> 是没有默认构造函数但带有接受 <span class="t-c"><span class="mw-geshi cpp source-cpp"><a href="cpp-utility-initializer_list.html"><span class="kw960">std::<span class="me2">initializer_list</span></span></a></span></span> 的构造函数的类类型,则进行<a href="cpp-language-list_initialization.html">列表初始化</a>。</p>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<p><br />
|
|
值初始化的效果是:</p>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-until-cxx11">
|
|
<td>
|
|
<div class="t-li1"><span class="t-li">1)</span> 如果 <code>T</code> 是拥有至少一个用户提供的任意种类的构造函数的类类型,则调用<a href="cpp-language-default_constructor.html">默认构造函数</a>;</div>
|
|
<div class="t-li1"><span class="t-li">2)</span> 如果 <code>T</code> 是没有任何用户提供的构造函数的非联合体类类型,则值初始化 T 的每个非静态数据成员与基类组分;</div>
|
|
</td>
|
|
<td><span class="t-mark-rev t-until-cxx11">(C++11 前)</span></td>
|
|
</tr>
|
|
<tr class="t-rev t-since-cxx11">
|
|
<td>
|
|
<div class="t-li1"><span class="t-li">1)</span> 如果 <code>T</code> 是没有<a href="cpp-language-default_constructor.html">默认构造函数</a>,或拥有用户提供的或被删除的<a href="cpp-language-default_constructor.html">默认构造函数</a>的类类型,则对象被<a href="cpp-language-default_initialization.html">默认初始化</a>;</div>
|
|
<div class="t-li1"><span class="t-li">2)</span> 如果 <code>T</code> 是拥有默认构造函数的类类型,而默认构造函数既没有被用户提供也没有被删除(即它可以是拥有隐式定义的或默认化的默认构造函数的类),则<a href="cpp-language-zero_initialization.html">零初始化</a>对象,然后如果它拥有非平凡的默认构造函数,则<a href="cpp-language-default_initialization.html">默认初始化</a>它;</div>
|
|
<div class="t-li1"><span class="t-li"></span> 然而在<a href="cpp-language-overload_resolution.html">重载决议</a>选择未被删除的默认化的默认构造函数时,所有已知编译器都进入情况 <span class="t-v">(2)</span>,即使有用户提供的默认构造函数,见注解;</div>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<div class="t-li1"><span class="t-li">3)</span> 如果 <code>T</code> 是数组类型,则值初始化数组的每个元素;</div>
|
|
<div class="t-li1"><span class="t-li">4)</span> 否则,零初始化对象。</div>
|
|
<h3><span class="mw-headline" id=".E6.B3.A8.E8.A7.A3">注解</span></h3>
|
|
<p>如果构造函数是用户声明的,且未在其首个声明上显式默认化,则它是<i>用户提供</i>的。</p>
|
|
<p>语法 <span class="t-c"><span class="mw-geshi cpp source-cpp">T object<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span></span></span> 不初始化对象;它声明一个不接受参数并返回 <code>T</code> 的函数。在 C++11 前值初始化一个具名变量的方式是 <span class="t-c"><span class="mw-geshi cpp source-cpp">T object <span class="sy1">=</span> T<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span></span></span>,它值初始化一个临时量然后复制初始化该对象:多数编译器在此情况下能<a href="cpp-language-copy_elision.html">优化掉复制</a>。</p>
|
|
<p>在 C++03(引入了值初始化)之前的 C++98 中,表达式 <span class="t-c"><span class="mw-geshi cpp source-cpp">new T<span class="br0">(</span><span class="br0">)</span></span></span> 被归类为默认初始化并指定进行零初始化。</p>
|
|
<p>引用不能被值初始化。</p>
|
|
<p>如<a href="cpp-language-explicit_cast.html">函数式转型</a>中所述,数组禁止语法 <span class="t-c"><span class="mw-geshi cpp source-cpp">T<span class="br0">(</span><span class="br0">)</span></span></span> <span class="t-v">(1)</span> ,但允许 <span class="t-c"><span class="mw-geshi cpp source-cpp">T<span class="br0">{</span><span class="br0">}</span></span></span> <span class="t-v">(5)</span>。</p>
|
|
<p>所有标准容器(<span class="t-lc"><a href="cpp-container-vector.html">std::vector</a></span>、<span class="t-lc"><a href="cpp-container-list.html">std::list</a></span> 等)在以单个 <code>size_type</code> 实参进行构造或由对 <span class="t-c"><span class="mw-geshi cpp source-cpp">resize<span class="br0">(</span><span class="br0">)</span></span></span> 的调用而增长时值初始化其各个元素,除非其分配器定制 <span class="t-c"><span class="mw-geshi cpp source-cpp">construct</span></span> 的行为。</p>
|
|
<p>从 C++11 起,对没有用户提供的构造函数而拥有类类型成员的类进行值初始化,其中成员的类拥有用户提供的构造函数,会在调用成员的构造函数前对成员清零:</p>
|
|
<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> i<span class="sy4">;</span>
|
|
A<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span> <span class="br0">}</span> <span class="co1">// 用户提供的默认构造函数,不初始化 i</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
|
|
<span class="kw1">struct</span> B <span class="br0">{</span> A a<span class="sy4">;</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> B<span class="br0">(</span><span class="br0">)</span>.<span class="me1">a</span>.<span class="me1">i</span> <span class="sy1"><<</span> <span class="st0">'<span class="es1">\n</span>'</span><span class="sy4">;</span> <span class="co1">// 值初始化 B 临时量</span>
|
|
<span class="co1">// C++03 中令 b.a.i 为未初始化</span>
|
|
<span class="co1">// C++11 中设 b.a.i 为零</span>
|
|
<span class="co1">// (注意 C++11 中 B{}.a.i 保留 b.a.i 为未初始化,但因为不同原因:</span>
|
|
<span class="co1">// 在 DR1301 后的 C++11 中,B{} 是聚合初始化,它值初始化拥有用户提供构造函数的 A)</span></pre></div>
|
|
</div>
|
|
<p>标准指定在类拥有用户提供的或被删除的默认构造函数时不进行零初始化,即使重载决议不选择该默认构造函数。所有已知编译器都在选择未被删除的默认化的默认构造函数时进行额外的零初始化。</p>
|
|
<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>
|
|
A<span class="br0">(</span><span class="br0">)</span> <span class="sy1">=</span> <span class="kw1">default</span><span class="sy4">;</span>
|
|
<span class="kw1">template</span><span class="sy1"><</span><span class="kw1">class</span> <span class="sy1">=</span> <span class="kw4">void</span><span class="sy1">></span>
|
|
A<span class="br0">(</span><span class="kw4">int</span> <span class="sy1">=</span> <span class="nu0">0</span><span class="br0">)</span> <span class="br0">{</span><span class="br0">}</span> <span class="co1">// A 拥有用户提供的默认构造函数,它没有被选择</span>
|
|
<span class="kw4">int</span> x<span class="sy4">;</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
|
|
<span class="kw4">constexpr</span> <span class="kw4">int</span> test<span class="br0">(</span>A a<span class="br0">)</span> <span class="br0">{</span>
|
|
<span class="kw1">return</span> a.<span class="me1">x</span><span class="sy4">;</span> <span class="co1">// 如果 a 的值不确定则行为未定义</span>
|
|
<span class="br0">}</span>
|
|
|
|
<span class="kw4">constexpr</span> <span class="kw4">int</span> zero <span class="sy1">=</span> test<span class="br0">(</span>A<span class="br0">(</span><span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="co1">// 谬构:按照标准不会零初始化形参,这导致未定义行为,并在要求常量求值的语境中使程序谬构。</span>
|
|
<span class="co1">// 然而所有已知编译器都接受这种代码。</span>
|
|
|
|
<span class="kw4">void</span> f<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span>
|
|
A a <span class="sy1">=</span> A<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 按照标准不被零初始化</span>
|
|
<span class="co1">// 但实现还是会生成零初始化的代码</span>
|
|
<span class="br0">}</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 <string></span>
|
|
<span class="co2">#include <vector></span>
|
|
<span class="co2">#include <iostream></span>
|
|
|
|
<span class="kw1">struct</span> T1
|
|
<span class="br0">{</span>
|
|
<span class="kw4">int</span> mem1<span class="sy4">;</span>
|
|
<a href="cpp-string-basic_string.html"><span class="kw1230">std::<span class="me2">string</span></span></a> mem2<span class="sy4">;</span>
|
|
<span class="br0">}</span><span class="sy4">;</span> <span class="co1">// 隐式默认构造函数</span>
|
|
|
|
<span class="kw1">struct</span> T2
|
|
<span class="br0">{</span>
|
|
<span class="kw4">int</span> mem1<span class="sy4">;</span>
|
|
<a href="cpp-string-basic_string.html"><span class="kw1230">std::<span class="me2">string</span></span></a> mem2<span class="sy4">;</span>
|
|
T2<span class="br0">(</span><span class="kw4">const</span> T2<span class="sy3">&</span><span class="br0">)</span> <span class="br0">{</span> <span class="br0">}</span> <span class="co1">// 用户提供的复制构造函数</span>
|
|
<span class="br0">}</span><span class="sy4">;</span> <span class="co1">// 无默认构造函数</span>
|
|
|
|
<span class="kw1">struct</span> T3
|
|
<span class="br0">{</span>
|
|
<span class="kw4">int</span> mem1<span class="sy4">;</span>
|
|
<a href="cpp-string-basic_string.html"><span class="kw1230">std::<span class="me2">string</span></span></a> mem2<span class="sy4">;</span>
|
|
T3<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span> <span class="br0">}</span> <span class="co1">// 用户提供的默认构造函数</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
|
|
<a href="cpp-string-basic_string.html"><span class="kw1230">std::<span class="me2">string</span></span></a> s<span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span> <span class="co1">// 类 => 默认初始化,值为 ""</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="br0">{</span><span class="br0">}</span><span class="sy4">;</span> <span class="co1">// 标量 => 零初始化,值为 0</span>
|
|
<span class="kw4">double</span> f <span class="sy1">=</span> <span class="kw4">double</span><span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 标量 => 零初始化,值为 0.0</span>
|
|
<span class="kw4">int</span><span class="sy2">*</span> a <span class="sy1">=</span> new <span class="kw4">int</span><span class="br0">[</span><span class="nu0">10</span><span class="br0">]</span><span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 数组 => 每个元素的值初始化</span>
|
|
<span class="co1">// 每个元素的值为 0</span>
|
|
T1 t1<span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span> <span class="co1">// 有隐式默认构造函数的类 =></span>
|
|
<span class="co1">// t1.mem1 被零初始化,值为 0</span>
|
|
<span class="co1">// t1.mem2 被默认初始化,值为 ""</span>
|
|
<span class="co1">// T2 t2{}; // 错误:类无默认构造函数</span>
|
|
T3 t3<span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span> <span class="co1">// 有用户提供默认构造函数的类 =></span>
|
|
<span class="co1">// t3.mem1 被默认初始化为不确定值</span>
|
|
<span class="co1">// t3.mem2 被默认初始化,值为 ""</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> v<span class="br0">(</span><span class="nu0">3</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 值初始化每个元素</span>
|
|
<span class="co1">// 每个元素的值为 0</span>
|
|
<a href="cpp-io-cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1"><<</span> s.<span class="me1">size</span><span class="br0">(</span><span class="br0">)</span> <span class="sy1"><<</span> <span class="st0">' '</span> <span class="sy1"><<</span> n <span class="sy1"><<</span> <span class="st0">' '</span> <span class="sy1"><<</span> f <span class="sy1"><<</span> <span class="st0">' '</span> <span class="sy1"><<</span> a<span class="br0">[</span><span class="nu0">9</span><span class="br0">]</span> <span class="sy1"><<</span> <span class="st0">' '</span> <span class="sy1"><<</span> v<span class="br0">[</span><span class="nu0">2</span><span class="br0">]</span> <span class="sy1"><<</span> <span class="st0">'<span class="es1">\n</span>'</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> t1.<span class="me1">mem1</span> <span class="sy1"><<</span> <span class="st0">' '</span> <span class="sy1"><<</span> t3.<span class="me1">mem1</span> <span class="sy1"><<</span> <span class="st0">'<span class="es1">\n</span>'</span><span class="sy4">;</span>
|
|
delete<span class="br0">[</span><span class="br0">]</span> a<span class="sy4">;</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">0 0 0 0 0
|
|
0 4199376</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/issue1301">CWG 1301</a></td>
|
|
<td>C++11</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-default_constructor.html">默认构造函数</a></li>
|
|
<li><a href="cpp-language-explicit.html"><code>explicit</code></a></li>
|
|
<li><a href="cpp-language-aggregate_initialization.html">聚合初始化</a></li>
|
|
<li><a href="cpp-language-list_initialization.html">列表初始化</a></li>
|
|
</ul>
|
|
</div>
|
|
<div class="visualClear"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|