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