⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 [10] constructors, c++ faq lite.htm

📁 c++faq。里面有很多关于c++的问题的解答。
💻 HTM
📖 第 1 页 / 共 4 页
字号:
<P><SMALL>[&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/ctors.html#top">Top</A> |&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/ctors.html#bottom">Bottom</A> |&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/inline-functions.html">Previous&nbsp;section</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/dtors.html">Next&nbsp;section</A> 
]</SMALL> 
<HR>

<P><A name=[10.9]></A>
<DIV class=FaqTitle>
<H3>[10.9] 为何不能在构造函数的初始化列表中初始化静态成员数据?<IMG alt=UPDATED! 
src="[10] Constructors, C++ FAQ Lite.files/updated.gif"></H3></DIV><SMALL><EM>[Recently 
added a "," in the initialization list thanks to <A 
href="mailto:tada@mail.wplus.net">Yaroslav Mironov</A> (on 4/01). <A 
href="http://www.sunistudio.com/cppfaq/ctors.html#[10.15]">Click here to go to 
the next FAQ in the "chain" of recent 
changes<!--rawtext:[10.15]:rawtext--></A>.]</EM></SMALL> 
<P>因为必须显式定义类的静态数据成员。 
<P><TT>Fred.h</TT>: 
<P>
<DIV 
class=CodeBlock><TT>&nbsp;class&nbsp;Fred&nbsp;{<BR>&nbsp;public:<BR>&nbsp;&nbsp;&nbsp;Fred();<BR>&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;...</EM><TT><BR>&nbsp;private:<BR>&nbsp;&nbsp;&nbsp;int&nbsp;i_;<BR>&nbsp;&nbsp;&nbsp;static&nbsp;int&nbsp;j_;<BR>&nbsp;}; 
</TT></DIV>
<P><TT>Fred.cpp</TT> (或 <TT>Fred.C</TT> 或其他): 
<P>
<DIV 
class=CodeBlock><TT>&nbsp;Fred::Fred()<BR>&nbsp;&nbsp;&nbsp;:&nbsp;i_(10)&nbsp;&nbsp;</TT><EM>//&nbsp;正确:能够(而且应该)这样初始化成员数据</EM><TT><BR>&nbsp;&nbsp;&nbsp;,&nbsp;j_(42)&nbsp;&nbsp;</TT><EM>//&nbsp;错误:不能象这样初始化静态成员数据</EM><TT><BR>&nbsp;{<BR>&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;...</EM><TT><BR>&nbsp;}<BR>&nbsp;<BR>&nbsp;</TT><EM>//&nbsp;必须这样定义静态数据成员:</EM><TT><BR>&nbsp;int&nbsp;Fred::j_&nbsp;=&nbsp;42; 
</TT></DIV>
<P><SMALL>[&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/ctors.html#top">Top</A> |&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/ctors.html#bottom">Bottom</A> |&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/inline-functions.html">Previous&nbsp;section</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/dtors.html">Next&nbsp;section</A> 
]</SMALL> 
<HR>

<P><A name=[10.10]></A>
<DIV class=FaqTitle>
<H3>[10.10] 为何有静态数据成员的类得到了链接错误?</H3></DIV>
<P>因为<A 
href="http://www.sunistudio.com/cppfaq/ctors.html#[10.9]">静态数据成员必须被显式定义在一个编辑单元中</A>。如果不这样做,你就可能得到<TT>"undefined&nbsp;external"</TT>链接错误。例如:
<P> 
<DIV 
class=CodeBlock><TT>&nbsp;</TT><EM>//&nbsp;Fred.h</EM><TT><BR>&nbsp;<BR>&nbsp;class&nbsp;Fred&nbsp;{<BR>&nbsp;public:<BR>&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;...</EM><TT><BR>&nbsp;private:<BR>&nbsp;&nbsp;&nbsp;static&nbsp;int&nbsp;j_;&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;声明静态数据成员:<TT>Fred::j_</TT></EM><TT><BR>&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;...</EM><TT><BR>&nbsp;}; 
</TT></DIV>
<P>链接器会向你抱怨(<TT>"Fred::j_&nbsp;is&nbsp;not&nbsp;defined"</TT>),除非你在一个源文件中定义(而不仅仅是声明)<TT>Fred::j_</TT>:
<P> 
<DIV 
class=CodeBlock><TT>&nbsp;</TT><EM>//&nbsp;Fred.cpp</EM><TT><BR>&nbsp;<BR>&nbsp;#include&nbsp;"Fred.h"<BR>&nbsp;<BR>&nbsp;int&nbsp;Fred::j_&nbsp;=&nbsp;some_expression_evaluating_to_an_int;<BR>&nbsp;<BR>&nbsp;</TT><EM>//&nbsp;Alternatively,&nbsp;if&nbsp;you&nbsp;wish&nbsp;to&nbsp;use&nbsp;the&nbsp;implicit&nbsp;0&nbsp;value&nbsp;for&nbsp;<TT>static</TT>&nbsp;<TT>int</TT>s:</EM><TT><BR>&nbsp;</TT><EM>//&nbsp;<TT>int&nbsp;Fred::j_;</TT></EM><TT> 
</TT></DIV>
<P>通常定义<TT>Fred</TT>类的静态数据成员的地方是<TT>Fred.cpp</TT>文件(或者<TT>Fred.C</TT>或者你使用的其他扩展名)。 

<P><SMALL>[&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/ctors.html#top">Top</A> |&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/ctors.html#bottom">Bottom</A> |&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/inline-functions.html">Previous&nbsp;section</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/dtors.html">Next&nbsp;section</A> 
]</SMALL> 
<HR>

<P><A name=[10.11]></A>
<DIV class=FaqTitle>
<H3>[10.11] 什么是“<TT>static</TT> initialization order fiasco”?</H3></DIV>
<P>你的项目的微妙杀手。
<P><EM><TT>static</TT> initialization order 
fiasco</EM>是对C++的一个非常微妙的并且常见的误解。不幸的是,错误发生在<TT>main()</TT>开始之前,很难检测到。
<P>简而言之,假设你有存在于不同的源文件<TT>x.cpp</TT> 和<TT>y.cpp</TT>的两个静态对象<TT>x</TT> 和 
<TT>y</TT>。再假定<TT>y</TT>对象的构造函数会调用<TT>x</TT>对象的某些方法。
<P>就是这些。就这么简单。
<P>结局是你完蛋不完蛋的机会是50%-50%。如果碰巧<TT>x.cpp</TT>的编辑单元先被初始化,这很好。但如果<TT>y.cpp</TT>的编辑单元先被初始化,然后<TT>y</TT>的构造函数比<TT>x</TT>的构造函数先运行。也就是说,<TT>y</TT>的构造函数会调用<TT>x</TT>对象的方法,而<TT>x</TT>对象还没有被构造。 

<P>我听说他们受雇于了麦当劳。享受他们的切碎肉的新工作去了。
<P>如果你觉得在卧室的一角玩俄罗斯方块是令人兴奋的,你可以到此为止。相反,如果你想通过用一种系统的方法防止灾难,来提高自己存活的机会,你可能想阅读<A 
href="http://www.sunistudio.com/cppfaq/ctors.html#[10.12]">下一个 FAQ<!--rawtext:[10.12]:rawtext--></A>。
<P>注意:static initialization order fiasco不作用于内建的/固有的类型,象<TT>int</TT> 或 
<TT>char*</TT>。例如,如果创建一个<TT>static</TT> 
<TT>float</TT>对象,不会有静态初始化次序的问题。静态初始化次序真正会崩溃的时机只有在你的<TT>static</TT>或全局对象有构造函数时。 
<P><SMALL>[&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/ctors.html#top">Top</A> |&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/ctors.html#bottom">Bottom</A> |&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/inline-functions.html">Previous&nbsp;section</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/dtors.html">Next&nbsp;section</A> 
]</SMALL> 
<HR>

<P><A name=[10.12]></A>
<DIV class=FaqTitle>
<H3>[10.12] 如何防止“<TT>static</TT> initialization order fiasco”?</H3></DIV>
<P>使用“首次使用时构造(construct on first use)”用法,意思就是简单地将静态对象包裹于函数内部。 
<P>例如,假设你有两个类,<TT>Fred</TT> 和 
<TT>Barney</TT>。有一个称为<TT>x</TT>的全局<TT>Fred</TT>对象,和一个称为<TT>y</TT>的全局<TT>Barney</TT>对象。<TT>Barney</TT>的构造函数调用了<TT>x</TT>对象的<TT>goBowling()</TT>方法。 
<TT>x.cpp</TT>文件定义了<TT>x</TT>对象: 
<P> 
<DIV 
class=CodeBlock><TT>&nbsp;</TT><EM>//&nbsp;File&nbsp;x.cpp</EM><TT><BR>&nbsp;#include&nbsp;"Fred.hpp"<BR>&nbsp;Fred&nbsp;x; 
</TT></DIV>
<P><TT>y.cpp</TT>文件定义了<TT>y</TT>对象: 
<P>
<DIV 
class=CodeBlock><TT>&nbsp;</TT><EM>//&nbsp;File&nbsp;y.cpp</EM><TT><BR>&nbsp;#include&nbsp;"Barney.hpp"<BR>&nbsp;Barney&nbsp;y; 
</TT></DIV>
<P><TT>Barney</TT>构造函数的全部看起来可能是象这样的: 
<P>
<DIV 
class=CodeBlock><TT>&nbsp;</TT><EM>//&nbsp;File&nbsp;Barney.cpp</EM><TT><BR>&nbsp;#include&nbsp;"Barney.hpp"<BR>&nbsp;<BR>&nbsp;Barney::Barney()<BR>&nbsp;{<BR>&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;...</EM><TT><BR>&nbsp;&nbsp;&nbsp;x.goBowling();<BR>&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;...</EM><TT><BR>&nbsp;} 
</TT></DIV>
<P>正如<A 
href="http://www.sunistudio.com/cppfaq/ctors.html#[10.11]">以上</A>所描述的,由于它们位于不同的源文件,那么 
<TT>y </TT>在 <TT>x </TT>之前构造而发生灾难的机率是50%。
<P>这个问题有许多解决方案,但一个非常简便的方案就是用一个返回<TT>Fred</TT>对象引用的全局函数<TT>x()</TT>,来取代全局的<TT>Fred</TT>对象 
<TT>x</TT>。
<P> 
<DIV 
class=CodeBlock><TT>&nbsp;</TT><EM>//&nbsp;File&nbsp;x.cpp</EM><TT><BR>&nbsp;<BR>&nbsp;#include&nbsp;"Fred.hpp"<BR>&nbsp;<BR>&nbsp;Fred&amp;&nbsp;x()<BR>&nbsp;{<BR>&nbsp;&nbsp;&nbsp;static&nbsp;Fred*&nbsp;ans&nbsp;=&nbsp;new&nbsp;Fred();<BR>&nbsp;&nbsp;&nbsp;return&nbsp;*ans;<BR>&nbsp;} 
</TT></DIV>
<P>由于静态局部对象只在控制流第一次越过它们的声明时构造,因此以上的<TT>new&nbsp;Fred()</TT>语句只会执行一次:<TT>x()</TT>被第一次调用时。每个后续的调用将返回同一个<TT>Fred</TT>对象(<TT>ans</TT>指向的那个)。然后你所要做的就是将 
<TT>x </TT>改成 <TT>x()</TT>: 
<P> 
<DIV 
class=CodeBlock><TT>&nbsp;</TT><EM>//&nbsp;File&nbsp;Barney.cpp</EM><TT><BR>&nbsp;#include&nbsp;"Barney.hpp"<BR>&nbsp;<BR>&nbsp;Barney::Barney()<BR>&nbsp;{<BR>&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;...</EM><TT><BR>&nbsp;&nbsp;&nbsp;x().goBowling();<BR>&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;...</EM><TT><BR>&nbsp;} 
</TT></DIV>
<P>由于该全局的<TT>Fred</TT>对象在首次使用时被构造,因此被称为<I>首次使用时构造用法(</I><EM>Construct On First 
Use Idiom)</EM> 
<P>这种方法的不利方面是<TT>Fred</TT>对象不会被析构。<EM>C++ FAQ Book</EM>有另一种技巧消除这个影响(但面临了“static 
<EM>de</EM>-initialization order fiasco”的代价)。
<P>注意:对于内建/固有类型,象<TT>int</TT> 或 
<TT>char*</TT>,不必这样做。例如,如果创建一个静态的或全局的<TT>float</TT>对象,不需要将它包裹于函数之中。静态初始化次序真正会崩溃的时机只有在你的<TT>static</TT>或全局对象有构造函数时。 

<P><SMALL>[&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/ctors.html#top">Top</A> |&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/ctors.html#bottom">Bottom</A> |&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/inline-functions.html">Previous&nbsp;section</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/dtors.html">Next&nbsp;section</A> 
]</SMALL> 
<HR>

<P><A name=[10.13]></A>
<DIV class=FaqTitle>
<H3>[10.13] 对于静态数据成员,如何防止“<TT>static</TT> initialization order 
fiasco”?</H3></DIV>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -