Merged from branch to trunk

[SVN r15572]
This commit is contained in:
Björn Karlsson 2002-09-30 16:54:26 +00:00
parent aff985a563
commit 7439073cbf

View File

@ -1,255 +1,219 @@
<!DOCTYPE HTML PUBLIC "-//SoftQuad Software//DTD HoTMetaL PRO 5.0::19981217::extensions to HTML 4.0//EN" "hmpro5.dtd"> <html>
<head>
<HTML> <meta http-equiv="Content-Type"
content="text/html; charset=iso-8859-1">
<title>value_initialized</title>
<HEAD> </head>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> <body vlink="#800080" link="#0000ff" text="#000000" bgcolor="#ffffff">
<META NAME="Template"
CONTENT="C:\PROGRAM FILES\MICROSOFT OFFICE\OFFICE\html.dot">
<META NAME="GENERATOR" CONTENT="Microsoft FrontPage Express 2.0">
<TITLE>Header </TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#0000FF" VLINK="#800080"> <h2><img src="../../c++boost.gif" width="276" height="86">
<H2><IMG SRC="../../c++boost.gif" WIDTH="276" HEIGHT="86">Header &lt;<A Header &lt;<a href="../../boost/utility/value_init.hpp">boost/utility/value_init.hpp</a>&gt;
HREF="../../boost/utility/aligned_storage.hpp">boost/utility/value_init.hpp</A>&gt; </h2>
</H2>
<H2>Contents</H2> <h2>Contents</h2>
<DL>
<DT><A HREF="#intro">Introduction</A></DT> <dl>
</DL> <dt><a href="#intro">Rationale</a></dt>
<UL> <dt><a href="#rationale">Introduction</a></dt>
<LI><A HREF="#valueinit">value-initialization</A></LI> </dl>
<LI><A HREF="#valueinitsyn">value-initialization syntax</A></LI>
</UL> <ul>
<DL CLASS="page-index"> <li><a href="#valueinit">value-initialization</a></li>
<DT><A HREF="#types">Types</A></DT> <li><a href="#valueinitsyn">value-initialization syntax</a></li>
</DL>
<UL> </ul>
<LI><A HREF="#val_init"><CODE>value_initialized&lt;&gt;</CODE></A></LI>
</UL> <dl class="page-index">
<HR> <dt><a href="#types">Types</a></dt>
<H2><A NAME="into"></A>Introduction</H2> </dl>
<P>The C++ standard document realeased by 1998 contains the definitions of
<CODE>zero-initialization</CODE> and <CODE>default-initialization</CODE>. <ul>
<li><a href="#val_init"><code>value_initialized&lt;&gt;</code></a></li>
</ul>
<a href="#acknowledgements">Acknowledgements</a><br>
<br>
<hr>
<h2><a name="rationale"></a>Rationale</h2>
<p>Constructing and initializing objects in a generic way is difficult in
C++. The problem is that there are several different rules that apply
for initialization. Depending on the type, the value of a newly constructed
object can be zero-initialized (logically 0), default-constructed (using
the default constructor), or indeterminate. When writing generic code,
this problem must be addressed. <code>value_initialized</code> provides
a solution with consistent syntax for value initialization of scalar,
union and class types. <br>
</p>
<h2><a name="into"></a>Introduction</h2>
<p>The C++ standard [<a href="#references">1</a>] contains the definitions
of <code>zero-initialization</code> and <code>default-initialization</code>.
Informally, zero-initialization means that the object is given the initial Informally, zero-initialization means that the object is given the initial
value 0 (converted to the type) and default-initialization means that POD types value 0 (converted to the type) and default-initialization means that
are zero-initialized while class types are initialized with their corresponding POD [<a href="#references">2</a>] types are zero-initialized, while class
default constructors. A <I>declaration</I> can contain an <I>initializer</I>, types are initialized with their corresponding default constructors. A
which specifies the object's initial value. The initializer can be just '()', <i>declaration</i> can contain an <i>initializer</i>, which specifies the
which determines that the object shall be default-initialized (but see below). object's initial value. The initializer can be just '()', which states that
However, if a <I>declaration</I> has no <I>initializer</I> and it is of a the object shall be default-initialized (but see below). However, if a <i>declaration</i>
non-const non-static POD type, the initial value is indeterminate:<CITE>(see has no <i>initializer</i> and it is of a non-<code>const</code>, non-<code>static</code>
8.5 for the accurate definitions)</CITE></P> POD type, the initial value is indeterminate:<cite>(see &sect;8.5 for the
<PRE>int x ; // no initializer. x value is indeterminate. accurate definitions).</cite></p>
std::string s ; // no initializer, s is default-constructed.
int y = int() ; <pre>int x ; // no initializer. x value is indeterminate.<br>std::string s ; // no initializer, s is default-constructed.<br><br>int y = int() ; <br>// y is initialized using copy-initialization<br>// but the temporary uses an empty set of parentheses as the initializer,<br>// so it is default-constructed.<br>// A default constructed POD type is zero-initialized,<br>// therefore, y == 0.<br><br>void foo ( std::string ) ;<br>foo ( std::string() ) ; <br>// the temporary string is default constructed <br>// as indicated by the initializer () </pre>
// y is initialized using copy-initialization
// but the temporary uses an empty set of parentheses as the initializer,
// so it is default-constructed.
// A default constructed POD type is zero-initialized,
// therefore, y == 0.
void foo ( std::string ) ; <h3><a name="valueinit">value-initialization</a></h3>
foo ( std::string() ) ;
// the temporary string is default constructed
// as indicated by the initializer () </PRE>
<H3><A NAME="valueinit">value-initialization</A></H3> <p>The first <a
<P>The first Technical Corrigendum for the C++ Standard (TC1), whose darft was href="http://anubis.dkuug.dk/JTC1/SC22/WG21/docs/cwg_defects.html">Technical
released to the public on Nov, 2001, introduced Core Issue 178 (among many Corrigendum for the C++ Standard</a> (TC1), whose draft was released to
other issues, of course).</P> the public in November 2001, introduced <a
<P> That issue introduced the new concept of <CODE>value-initialization</CODE> href="http://anubis.dkuug.dk/JTC1/SC22/WG21/docs/cwg_defects.html#178">Core
(it also fixed the wording for zero-initialization). Informally, Issue 178</a> (among many other issues, of course).</p>
value-initialization is similar to default-initialization with the exception
that on some cases non static data members and base class sub-objects are also
value-initialized. The difference is that an object which is value-initialized
won't have (or at least it is less likely to have) indeterminate values for
data members and base class sub-objects; unlike the case of an object default
constructed. (see Core Issue 178 for a normative description)</P>
<P>In order to specify value-initialization of an object we need to use the
empty-set initializer: (). </P>
<P><I>(but recall that the released official Std document says that '()'
invokes default-initialization, not value-initialization as it is now)</I></P>
<P>As before, a declaration with no intializer specifies
default-initialization, and a declaration with a non-empty initializer
specifies copy (=xxx) or direct (xxx) initialization. </P>
<PRE>template&lt;class T&gt; void eat(T);
int x ; // indeterminate initial value.
std::string s; // default-initialized.
eat ( int() ) ; // value-initialized
eat ( std::string() ) ; // value-initialied</PRE>
<H4><A NAME="valueinitsyn">value-initialization</A> syntax</H4> <p> That issue introduced the new concept of <code>value-initialization</code>
<P>Value initialization is specified using (). However, the empty set of (it also fixed the wording for zero-initialization). Informally, value-initialization
parentheses is not permited by the syntax of the initializer because it is is similar to default-initialization with the exception that in some cases
parsed as the declaration of a function taking no arguments: </P> non-static data members and base class sub-objects are also value-initialized.
<PRE>int x() ; // declares function int(*)() The difference is that an object that is value-initialized won't have
int y ( int() ) ; // decalares function int(*)( int(*)() )</PRE> (or at least is less likely to have) indeterminate values for data members
and base class sub-objects; unlike the case of an object default constructed.
(see Core Issue 178 for a normative description).</p>
<P>Thus, the empty () must be put in some other initialization context.</P> <p>In order to specify value-initialization of an object we need to use the
<P>One alternative is to use copy-initialization syntax:</P> empty-set initializer: (). </p>
<PRE>int x = int() ;</PRE>
<P>This works perfectly fine for POD types. But for non-POD class types, <p><i>(but recall that the current C++ Standard states that '()' invokes default-initialization,
copy-initialization searches for a suitable constructor, which could be, for not value-initialization)</i></p>
instance, the copy-constructor (it also searches for a suitable conversion
sequence but this doesn't apply in our context). For an arbitrary unknown type,
using this syntax may not have the value-initialization effect intended because
we don't know if a copy from a default constructed object is exactly the same
as a default constructed object, and the compiler is allowed (in some cases)
but never required to optimize the copy away.</P>
<P>One possible generic solution is to use value-initialization of a non static
data member:</P>
<PRE>template&lt;class T&gt;
struct W
{
// value-initialization of 'data' here.
W() : data() {}
T data ;
} ;
W&lt;int&gt; w ;
// w.data is value-initialized for any type. </PRE>
<P>This is the solution supplied by the value_initialized&lt;&gt; template <p>As before, a declaration with no intializer specifies default-initialization,
class.</P> and a declaration with a non-empty initializer specifies copy (=xxx) or
<H2><A NAME="types"></A>Types</H2> direct (xxx) initialization. </p>
<H2><A NAME="val_init"><CODE>template class
value_initialized&lt;T&gt;</CODE></A></H2>
<PRE>namespace boost {
template&lt;class T&gt; <pre>template&lt;class T&gt; void eat(T);<br>int x ; // indeterminate initial value.<br>std::string s; // default-initialized.<br>eat ( int() ) ; // value-initialized<br>eat ( std::string() ) ; // value-initialied</pre>
class value_initialized
{
public :
value_initialized() : x() {} <h4><a name="valueinitsyn">value-initialization</a> syntax</h4>
operator T&amp;() const { return x ; } <p>Value initialization is specified using (). However, the empty set of
parentheses is not permitted by the syntax of initializers because it is
parsed as the declaration of a function taking no arguments: </p>
T&amp; data() const { return x ; } <pre>int x() ; // declares function int(*)()<br>int y ( int() ) ; // decalares function int(*)( int(*)() )</pre>
private : <p>Thus, the empty () must be put in some other initialization context.</p>
<I>impll-defined</I> x ; <p>One alternative is to use copy-initialization syntax:</p>
} ;
template&lt;class T&gt; <pre>int x = int() ;</pre>
T const&amp; get ( value_initialized&lt;T&gt; const&amp; x )
{
return x.data() ;
}
template&lt;class T&gt;
T&amp; get ( value_initialized&lt;T&gt;&amp; x )
{
return x.data() ;
}
} // namespace boost <p>This works perfectly fine for POD types. But for non-POD class types,
</PRE> copy-initialization searches for a suitable constructor, which could be,
for instance, the copy-constructor (it also searches for a suitable conversion
sequence but this doesn't apply in this context). For an arbitrary unknown
type, using this syntax may not have the value-initialization effect intended
because we don't know if a copy from a default constructed object is exactly
the same as a default constructed object, and the compiler is allowed (in
some cases), but never required to, optimize the copy away.</p>
<P>An object of this template class is a T-wrapper convertible to <p>One possible generic solution is to use value-initialization of a non static
<CODE>'T&amp;'</CODE> whose wrapped object (data member of type T) is data member:</p>
<A HREF="#valueinit">value-initialized</A> upon default-initialization of this
wrapper class: </P>
<PRE>
int zero = 0 ;
value_initialized&lt;int&gt; x ;
assert ( x == zero ) ;
std::string def ; <pre>template&lt;class T&gt; <br>struct W <br>{<br> // value-initialization of 'data' here.<br> W() : data() {}<br> T data ;<br>} ;<br>W&lt;int&gt; w ;<br>// w.data is value-initialized for any type. </pre>
value_initialized&lt; std::string &gt; y ;
assert ( y == def ) ;
</PRE>
<P>The purpose of this wrapper is to provide a consistent syntax for value <p><code>This is the solution supplied by the value_initialized&lt;&gt; template
initialization of scalar, union and class types (POD and non-POD) since the class.</code></p>
correct syntax for value initialization varies (see <A
HREF="#valueinitsyn">value-initialization syntax</A>)</P>
<P>The wrapped object can be accessed either through the conversion operator
T&amp;, the member function data(), or the non-member friend function get():
</P>
<PRE>void watch(int);
value_initialized&lt;int&gt; x;
watch(x) ; // operator T&amp; used. <h2><a name="types"></a>Types</h2>
watch(x.data());
watch( get(x) ) // friend function get() used</PRE>
<P>Both <CODE>const and non-const</CODE> objects can be wrapped. Non-constant <h2><a name="val_init"><code>template class value_initialized&lt;T&gt;</code></a></h2>
objects can be modified directly from within the wrapper but constant objects
cannot:</P>
<PRE>value_initialized&lt;int&gt; x ;
static_cast&lt;int&amp;&gt;(x) = 1 ; // OK
get(x) = 1 ; // OK
value_initialized&lt;int const&gt; y ; <pre>namespace boost {<br><br>template&lt;class T&gt;<br>class value_initialized<br>{<br> public :<br> value_initialized() : x() {}<br> operator T&amp;() const { return x ; }<br> T&amp; data() const { return x ; }<br><br> private :<br> <i>impll-defined</i> x ;<br>} ;<br><br>template&lt;class T&gt;<br>T const&amp; get ( value_initialized&lt;T&gt; const&amp; x )<br>{<br> return x.data() ;<br>}<br><br>template&lt;class T&gt;<br>T&amp; get ( value_initialized&lt;T&gt;&amp; x )<br>{<br> return x.data() ;<br>}<br><br>} // namespace boost<br></pre>
static_cast&lt;int&amp;&gt;(y) = 1 ; // ERROR: cannot cast to int&amp;
static_cast&lt;int const&amp;&gt;(y) = 1 ; // ERROR: cannot modify a const value
get(y) = 1 ; // ERROR: cannot modify a const value</PRE>
<H3>warning:</H3> <p>An object of this template class is a <code>T</code>-wrapper convertible
<BLOCKQUOTE> <P>Both the conversion operator and the data() member function are to <code>'T&amp;'</code> whose wrapped object (data member of type <code>T</code>)
<CODE>const</CODE> in order to allow access to the wrapped object from a is <a href="#valueinit">value-initialized</a> upon default-initialization
constant wrapper:</P> of this wrapper class: </p>
<PRE>void foo(int);
value_initialized&lt;int&gt; const x ;
foo(x);
</PRE>
<P>But notice that this conversion operator is to <CODE>T&amp;</CODE> but it is <pre>int zero = 0 ;<br>value_initialized&lt;int&gt; x ;<br>assert ( x == zero ) ;<br><br>std::string def ;<br>value_initialized&lt; std::string &gt; y ;<br>assert ( y == def ) ;<br></pre>
itself <CODE>const</CODE>. As a consequence, if T is a non-const type, you can
modify the wrapped object even from within a constant wrapper:</P>
<PRE>value_initialized&lt;int&gt; const x_c ;
int&amp; xr = x_c ; // OK, conversion to int&amp; available even though x_c is itself const.
xr = 2 ; </PRE>
<P>The reason for this obscure behaviour is that some commonly used compilers <p>The purpose of this wrapper is to provide a consistent syntax for value
just don't accept the following valid code:</P> initialization of scalar, union and class types (POD and non-POD) since
<PRE> the correct syntax for value initialization varies (see <a
struct X href="#valueinitsyn">value-initialization syntax</a>)</p>
{
operator int&amp;() ;
operator int const&amp;() const ;
};
X x ;
(x == 1 ) ; // ERROR HERE!</PRE>
<P>These compilers complain about ambiguity between the conversion operators. <p>The wrapped object can be accessed either through the conversion operator
<BR> <code>T&amp;</code>, the member function <code>data()</code>, or the
This is strictly wrong, but the only workaround that I know about is to provide non-member function <code>get()</code>: </p>
only one of them, which leads to the obscure behaviour just explained.</P>
</BLOCKQUOTE>
<H3>Recomended practice: the non-member non-friend get() idiom</H3>
<P>The obscure behaviour just warned about being able to modify a non-const
wrapped object from within a constant wrapper can be avoided if access to the
wrapped object is always done through the get() idiom:</P>
<PRE>value_initialized&lt;int&gt; x ;
get(x) = 1 ; // OK
value_initialized&lt;int const&gt; cx ; <pre>void watch(int);<br>value_initialized&lt;int&gt; x;<br><br>watch(x) ; // operator T&amp; used.<br>watch(x.data());<br>watch( get(x) ) // function get() used</pre>
get(x) = 1 ; // ERROR: Cannot modify a const object
value_initialized&lt;int&gt; const x_c ; <p>Both <code>const</code> and non-<code>const</code> objects can be wrapped.
get(x_c) = 1 ; // ERROR: Cannot modify a const object Mutable objects can be modified directly from within the wrapper but constant
objects cannot:</p>
value_initialized&lt;int const&gt; const cx_c ; <pre>value_initialized&lt;int&gt; x ; <br>static_cast&lt;int&amp;&gt;(x) = 1 ; // OK<br>get(x) = 1 ; // OK<br><br>value_initialized&lt;int const&gt; y ; <br>static_cast&lt;int&amp;&gt;(y) = 1 ; // ERROR: cannot cast to int&amp;<br>static_cast&lt;int const&amp;&gt;(y) = 1 ; // ERROR: cannot modify a const value<br>get(y) = 1 ; // ERROR: cannot modify a const value</pre>
get(cx_c) = 1 ; // ERROR: Cannot modify a const object
</PRE>
<HR> <h3>Warning:</h3>
<P>Revised 23 August 2002</P>
<P>&copy; Copyright boost.org 2002. Permission to copy, use, modify, sell and
distribute this document is granted provided this copyright notice appears in
all copies. This document is provided &quot;as is&quot; without express or
implied warranty, and with no claim as to its suitability for any purpose.</P>
<P>Developed by <A HREF="mailto:fcacciola@gosierra.com">Fernando Cacciola</A>,
the latest version of this file can be found at <A
HREF="http://www.boost.org">www.boost.org</A>, and the boost discussion list at
<A
HREF="http://www.yahoogroups.com/list/boost">www.yahoogroups.com/list/boost</A>.
</P>
</BODY>
</HTML>
<p>Both the conversion operator and the <code>data()</code> member function
are <code>const</code> in order to allow access to the wrapped object
from a constant wrapper:</p>
<pre>void foo(int);<br>value_initialized&lt;int&gt; const x ;<br>foo(x);<br></pre>
<p>But notice that this conversion operator is to <code>T&amp;</code> although
it is itself <code>const</code>. As a consequence, if <code>T</code> is
a non-<code>const</code> type, you can modify the wrapped object even from
within a constant wrapper:</p>
<pre>value_initialized&lt;int&gt; const x_c ;<br>int&amp; xr = x_c ; // OK, conversion to int&amp; available even though x_c is itself const.<br>xr = 2 ; </pre>
<p>The reason for this obscure behavior is that some commonly used compilers
just don't accept the following valid code:</p>
<pre>struct X<br>{<br> operator int&amp;() ;<br> operator int const&amp;() const ; <br>};<br>X x ;<br>(x == 1 ) ; // ERROR HERE!</pre>
<p>These compilers complain about ambiguity between the conversion operators.
This complaint is incorrect, but the only workaround that I know of is
to provide only one of them, which leads to the obscure behavior just explained.<br>
</p>
<h3>Recommended practice: The non-member get() idiom</h3>
<p>The obscure behavior of being able to modify a non-<code>const</code>
wrapped object from within a constant wrapper can be avoided if access to
the wrapped object is always performed with the <code>get()</code> idiom:</p>
<pre>value_initialized&lt;int&gt; x ;<br>get(x) = 1 ; // OK<br><br>value_initialized&lt;int const&gt; cx ;<br>get(x) = 1 ; // ERROR: Cannot modify a const object<br><br>value_initialized&lt;int&gt; const x_c ;<br>get(x_c) = 1 ; // ERROR: Cannot modify a const object<br><br>value_initialized&lt;int const&gt; const cx_c ;<br>get(cx_c) = 1 ; // ERROR: Cannot modify a const object<br></pre>
<h3><a name="references">References</a></h3>
[1] The C++ Standard, ISO/IEC 14882:98 <br>
[2] Plain Old Data
<h3><a name="acknowledgements"></a>Acknowledgements</h3>
value_initialized was developed by Fernando Cacciola, with help and
suggestions from David Abrahams and Darin Adler.<br>
Special thanks to Björn Karlsson who carefully edited and completed this documentation.
<pre>&nbsp;</pre>
<hr>
<p>Revised 19 September 2002</p>
<p>&copy; Copyright boost.org 2002. Permission to copy, use, modify, sell
and distribute this document is granted provided this copyright notice appears
in all copies. This document is provided "as is" without express or implied
warranty, and with no claim as to its suitability for any purpose.</p>
<p>Developed by <a href="mailto:fernando_cacciola@hotmail.com">Fernando Cacciola</a>,
the latest version of this file can be found at <a
href="http://www.boost.org">www.boost.org</a>, and the boost discussion list
at <a href="http://www.yahoogroups.com/list/boost">www.yahoogroups.com/list/boost</a>.
</p>
<br>
<br>
</body>
</html>