166 lines
25 KiB
HTML
166 lines
25 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_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>变量的<i>初始化</i>在构造时提供其初值。</p>
|
|
<p>初值可以由<a href="cpp-language-declarations.html">声明符</a>或 <a href="cpp-language-new.html">new 表达式</a>的初始化器部分提供。在函数调用时也会发生:函数形参及函数返回值也会被初始化。</p>
|
|
<p>对于每个声明符,初始化器必须是下列之一:</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> <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>=</b></code> <span class="t-spar">表达式</span></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><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>
|
|
</table>
|
|
<div class="t-li1"><span class="t-li">1)</span> 括号中的以逗号分隔的含有任意表达式和花括号初始化器列表的列表</div>
|
|
<div class="t-li1"><span class="t-li">2)</span> 等号后面跟着一个表达式</div>
|
|
<div class="t-li1"><span class="t-li">3)</span> 花括号初始化器列表:以逗号分隔且可以为空的含有表达式和其他花括号初始化器列表的列表</div>
|
|
<p>根据上下文,初始化器可以调用:</p>
|
|
<ul>
|
|
<li><a href="cpp-language-value_initialization.html">值初始化</a>,例如 <span class="t-c"><span class="mw-geshi cpp source-cpp"><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></span></li>
|
|
<li><a href="cpp-language-direct_initialization.html">直接初始化</a>,例如 <span class="t-c"><span class="mw-geshi cpp source-cpp"><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="st0">"hello"</span><span class="br0">)</span><span class="sy4">;</span></span></span></li>
|
|
<li><a href="cpp-language-copy_initialization.html">复制初始化</a>,例如 <span class="t-c"><span class="mw-geshi cpp source-cpp"><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">"hello"</span><span class="sy4">;</span></span></span></li>
|
|
<li><a href="cpp-language-list_initialization.html">列表初始化</a>,例如 <span class="t-c"><span class="mw-geshi cpp source-cpp"><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="st0">'a'</span>, <span class="st0">'b'</span>, <span class="st0">'c'</span><span class="br0">}</span><span class="sy4">;</span></span></span></li>
|
|
<li><a href="cpp-language-aggregate_initialization.html">聚合初始化</a>,例如 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">char</span> a<span class="br0">[</span><span class="nu0">3</span><span class="br0">]</span> <span class="sy1">=</span> <span class="br0">{</span><span class="st0">'a'</span>, <span class="st0">'b'</span><span class="br0">}</span><span class="sy4">;</span></span></span></li>
|
|
<li><a href="cpp-language-reference_initialization.html">引用初始化</a>,例如 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">char</span><span class="sy3">&</span> c <span class="sy1">=</span> a<span class="br0">[</span><span class="nu0">0</span><span class="br0">]</span><span class="sy4">;</span></span></span></li>
|
|
</ul>
|
|
<p>如果不提供初始化器,那么<a href="cpp-language-default_initialization.html">默认初始化</a>的规则会被应用。</p>
|
|
<h3><span class="mw-headline" id=".E9.9D.9E.E5.B1.80.E9.83.A8.E5.8F.98.E9.87.8F">非局部变量</span></h3>
|
|
<p>所有具有静态<a href="cpp-language-storage_duration.html">存储期</a>的非局部变量的初始化会作为程序启动的一部分在 <a href="cpp-language-main_function.html">main 函数</a>的执行之前进行(除非被延迟,见下文)。所有具有线程局部存储期的非局部变量的初始化会作为线程启动的一部分进行,按顺序早于线程函数的执行开始。对于这两种变量,初始化发生于两个截然不同的阶段:</p>
|
|
<h4><span class="mw-headline" id=".E9.9D.99.E6.80.81.E5.88.9D.E5.A7.8B.E5.8C.96">静态初始化</span></h4>
|
|
<p>有两种静态初始化的形式:</p>
|
|
<div class="t-li1"><span class="t-li">1)</span> 如果相关,则应用<a href="cpp-language-constant_initialization.html">常量初始化</a>。</div>
|
|
<div class="t-li1"><span class="t-li">2)</span> 否则非局部静态及线程局域变量会被<a href="cpp-language-zero_initialization.html">零初始化</a>。</div>
|
|
<p>实践中:</p>
|
|
<ul>
|
|
<li>常量初始化通常在编译期进行。预先被计算的对象表示会作为程序映像的一部分存储下来。如果编译器没有这样做,那么它仍然必须保证该初始化发生早于任何动态初始化。</li>
|
|
<li>零初始化的变量将被置于程序映像的 <code>.bss</code> 段,它不占据磁盘空间,并在加载程序时由操作系统以零填充。</li>
|
|
</ul>
|
|
<h4><span class="mw-headline" id=".E5.8A.A8.E6.80.81.E5.88.9D.E5.A7.8B.E5.8C.96">动态初始化</span></h4>
|
|
<p>在所有静态初始化完成后,在下列情形中进行非局部变量的动态初始化:</p>
|
|
<div class="t-li1"><span class="t-li">1)</span> <i>无序的动态初始化</i>,仅适用于未被<a href="cpp-language-template_specialization.html">显式特化</a>的(静态/线程局域)类模板的<a href="cpp-language-static.html">静态数据成员</a><span class="t-rev-inl t-since-cxx14"><span>及<a href="cpp-language-variable_template.html">变量模板</a></span> <span><span class="t-mark-rev t-since-cxx14">(C++14 起)</span></span></span>。这些静态变量的初始化相对于所有其他动态初始化之间是顺序不确定的<span class="t-rev-inl t-since-cxx17"><span>,除非程序在初始化某个变量之前开始了一个线程,此时初始化则是无顺序的</span> <span><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></span></span>。这些线程局域变量的初始化相对于所有其他动态初始化之间是无顺序的。</div>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx17">
|
|
<td>
|
|
<div class="t-li1"><span class="t-li">2)</span> <i>部分有序的动态初始化</i>,适用于并未被隐式或显式实例化的特化的所有 inline 变量。如果一个部分有序的 V 在每个翻译单元中比有序或部分有序的 W 更早定义,那么 V 的初始化按顺序早于(或若程序启动了线程,则为先发生于)W 的初始化。</div>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<div class="t-li1"><span class="t-li">3)</span> <i>有序的动态初始化</i>,适用于所有其他非局部变量:在单个翻译单元中,这些变量的初始化始终严格以其定义出现于源代码中的顺序<a href="cpp-language-eval_order.html">定序</a>。不同翻译单元中的静态变量的初始化之间是顺序不确定的。不同翻译单元中的线程局域变量的初始化之间是无顺序的。</div>
|
|
<p>当拥有静态或线程存储期的非局部变量的初始化通过异常退出时,调用 <span class="t-lc"><a href="cpp-error-terminate.html">std::terminate</a></span>。</p>
|
|
<h4><span class="mw-headline" id=".E6.8F.90.E6.97.A9.E5.8A.A8.E6.80.81.E5.88.9D.E5.A7.8B.E5.8C.96">提早动态初始化</span></h4>
|
|
<p>在下列条件都满足的情况下,允许编译器将初始化动态初始化的变量作为静态初始化(实为编译期)的一部分:</p>
|
|
<div class="t-li1"><span class="t-li">1)</span> 初始化的动态版本不改变命名空间作用域中任何先于其初始化的对象的值</div>
|
|
<div class="t-li1"><span class="t-li">2)</span> 初始化的静态版本在被初始化变量中产生的值,与当所有不要求静态初始化的变量都被动态初始化时,由动态初始化所生成的值相同。</div>
|
|
<p>因为上述规则,如果某对象 <code>o1</code> 的初始化涉及到命名空间作用域对象 <code>o2</code>,而它潜在地要求动态初始化,但在同一翻译单元中在其之后定义,那么不指明所用的 <code>o2</code> 是完全初始化的 <code>o2</code> 的值(因为编译器把 <code>o2</code> 的初始化提升到编译时)还是 <code>o2</code> 仅被零初始化的值。</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">inline</span> <span class="kw4">double</span> fd<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span> <span class="kw1">return</span> <span class="nu16">1.0</span><span class="sy4">;</span> <span class="br0">}</span>
|
|
<span class="kw4">extern</span> <span class="kw4">double</span> d1<span class="sy4">;</span>
|
|
<span class="kw4">double</span> d2 <span class="sy1">=</span> d1<span class="sy4">;</span> <span class="co1">// 未指明:</span>
|
|
<span class="co1">// 如果 d1 被动态初始化则动态初始化为 0.0,或</span>
|
|
<span class="co1">// 如果 d1 被静态初始化则动态初始化为 1.0,或</span>
|
|
<span class="co1">// 静态初始化为 0.0(因为当两个变量都被动态初始化时将为这个值)</span>
|
|
<span class="kw4">double</span> d1 <span class="sy1">=</span> fd<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 可能静态或动态初始化为 1.0</span></pre></div>
|
|
</div>
|
|
<h4><span class="mw-headline" id=".E5.BB.B6.E8.BF.9F.E5.8A.A8.E6.80.81.E5.88.9D.E5.A7.8B.E5.8C.96">延迟动态初始化</span></h4>
|
|
<p>动态初始化是发生早于(对于静态变量)主函数或(对于线程局域变量)其线程的首个函数的首条语句,还是延迟到发生晚于它们,是由实现定义的。</p>
|
|
<p>如果<span class="t-rev-inl t-since-cxx17"><span>非内联变量</span> <span><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></span></span>的初始化延迟到发生晚于主/线程函数的首条语句,那么它发生早于与所初始化的变量定义于同一翻译单元中的任何拥有静态/线程存储期的变量的首次 <a href="cpp-language-definition.html#ODR_.E5.BC.8F.E4.BD.BF.E7.94.A8">ODR 式使用</a>。若给定翻译单元中没有 ODR 式使用变量或函数,则定义于该翻译单元的非局部变量可能始终不被初始化(这模仿按需的动态库的行为)。然而,只要翻译单元中 ODR 式使用了任何事物,就会初始化所有在初始化或销毁中拥有副作用的非局部变量,即使程序中没有用到它们。</p>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx17">
|
|
<td>
|
|
<p>如果内联变量的初始化被延迟,那么它发生早于这个特定变量的首次 <a href="cpp-language-definition.html#ODR_.E5.BC.8F.E4.BD.BF.E7.94.A8">ODR 式使用</a>。</p>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="co1">// - 文件 1 -</span>
|
|
<span class="co2">#include "a.h"</span>
|
|
<span class="co2">#include "b.h"</span>
|
|
B b<span class="sy4">;</span>
|
|
A<span class="sy4">::</span><span class="me2">A</span><span class="br0">(</span><span class="br0">)</span><span class="br0">{</span> b.<span class="me1">Use</span><span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="br0">}</span>
|
|
|
|
<span class="co1">// - 文件 2 -</span>
|
|
<span class="co2">#include "a.h"</span>
|
|
A a<span class="sy4">;</span>
|
|
|
|
<span class="co1">// - 文件 3 -</span>
|
|
<span class="co2">#include "a.h"</span>
|
|
<span class="co2">#include "b.h"</span>
|
|
<span class="kw4">extern</span> A a<span class="sy4">;</span>
|
|
<span class="kw4">extern</span> B b<span class="sy4">;</span>
|
|
|
|
<span class="kw4">int</span> main<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span>
|
|
a.<span class="me1">Use</span><span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span>
|
|
b.<span class="me1">Use</span><span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="br0">}</span>
|
|
|
|
<span class="co1">// 如果 a 在进入 main 之前被初始化,那么 b 可能在 A::A() 使用它的时间点仍未被初始化</span>
|
|
<span class="co1">// (因为动态初始化在翻译单元间是顺序不确定的)</span>
|
|
|
|
<span class="co1">// 如果 a 在某个 main 的首条语句之后的时间点初始化</span>
|
|
<span class="co1">// (它 ODR 式使用了定义于文件 1 的函数,强制其初始化得以运行),</span>
|
|
<span class="co1">// 那么 b 将在 A::A 使用它前初始化</span></pre></div>
|
|
</div>
|
|
<h3><span class="mw-headline" id=".E9.9D.99.E6.80.81.E5.B1.80.E9.83.A8.E5.8F.98.E9.87.8F">静态局部变量</span></h3>
|
|
<p>有关局部(即块作用域)的静态和线程局部变量,见<a href="cpp-language-storage_duration.html#.E9.9D.99.E6.80.81.E5.B1.80.E9.83.A8.E5.8F.98.E9.87.8F">静态局部变量</a>。</p>
|
|
<p>拥有<a href="cpp-language-storage_duration.html#.E8.BF.9E.E6.8E.A5">外部或内部链接</a>的变量的块作用域声明中不允许初始化器。这种声明必须带 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">extern</span></span></span> 出现而且不能为定义。</p>
|
|
<h3><span class="mw-headline" id=".E7.B1.BB.E6.88.90.E5.91.98">类成员</span></h3>
|
|
<p>非静态数据成员可以<a href="cpp-language-initializer_list.html" class="mw-redirect">成员初始化器列表</a>或以<a href="cpp-language-data_members.html#.E6.88.90.E5.91.98.E5.88.9D.E5.A7.8B.E5.8C.96">默认成员初始化器</a>初始化。</p>
|
|
<h3><span class="mw-headline" id=".E6.B3.A8.E8.A7.A3">注解</span></h3>
|
|
<p>非局部变量的销毁顺序在 <span class="t-lc"><a href="cpp-utility-program-exit.html">std::exit</a></span> 中描述。</p>
|
|
<h3><span class="mw-headline" id=".E5.8F.82.E9.98.85">参阅</span></h3>
|
|
<ul>
|
|
<li><a href="cpp-language-copy_elision.html">复制消除</a></li>
|
|
<li><a href="cpp-language-converting_constructor.html">转换构造函数</a></li>
|
|
<li><a href="cpp-language-copy_constructor.html">复制构造函数</a></li>
|
|
<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-move_constructor.html">移动构造函数</a></li>
|
|
<li><a href="cpp-language-new.html">new</a></li>
|
|
</ul>
|
|
<table class="t-dsc-begin"></table>
|
|
</div>
|
|
<div class="visualClear"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|