File: value_init.htm

package info (click to toggle)
boost 1.34.1-14
  • links: PTS
  • area: main
  • in suites: lenny
  • size: 116,412 kB
  • ctags: 259,566
  • sloc: cpp: 642,395; xml: 56,450; python: 17,612; ansic: 14,520; sh: 2,265; yacc: 858; perl: 481; makefile: 478; lex: 94; sql: 74; csh: 6
file content (219 lines) | stat: -rw-r--r-- 12,753 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
<html>
<head>
             
  <meta http-equiv="Content-Type"
 content="text/html; charset=iso-8859-1">
  <title>value_initialized</title>
    
</head>
  <body vlink="#800080" link="#0000ff" text="#000000" bgcolor="#ffffff">
                   
<h2><img src="../../boost.png" width="276" height="86">
         Header &lt;<a href="../../boost/utility/value_init.hpp">boost/utility/value_init.hpp</a>&gt;
     </h2>
                   
<h2>Contents</h2>
                   
<dl>
  <dt><a href="#rationale">Rationale</a></dt>
  <dt><a href="#intro">Introduction</a></dt>
</dl>
                   
<ul>
          <li><a href="#valueinit">value-initialization</a></li>
          <li><a href="#valueinitsyn">value-initialization syntax</a></li>
                   
</ul>
                   
<dl class="page-index">
  <dt><a href="#types">Types</a></dt>
</dl>
                   
<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="intro"></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
     value 0 (converted to the type) and default-initialization means that
 POD   [<a href="#references">2</a>] types are zero-initialized, while class
 types   are initialized with their corresponding default constructors. A
<i>declaration</i>   can contain an <i>initializer</i>, which specifies the
object's initial value.  The initializer can be just '()', which states that
the object shall be default-initialized  (but see below). However, if a <i>declaration</i> 
  has no <i>initializer</i>  and it is of a non-<code>const</code>, non-<code>static</code> 
   POD type, the initial value is indeterminate:<cite>(see &sect;8.5 for the
   accurate definitions).</cite></p>
                   
<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>
                    
<h3><a name="valueinit">value-initialization</a></h3>
                   
<p>The first <a
 href="http://anubis.dkuug.dk/JTC1/SC22/WG21/docs/cwg_defects.html">Technical 
  Corrigendum for the C++ Standard</a> (TC1), whose draft   was released to
  the public in November 2001, introduced <a
 href="http://anubis.dkuug.dk/JTC1/SC22/WG21/docs/cwg_defects.html#178">Core 
  Issue 178</a> (among   many other issues, of course).</p>
                   
<p> That issue introduced the new concept of <code>value-initialization</code>
     (it also fixed the wording for zero-initialization). Informally, value-initialization 
    is similar to default-initialization with the exception that in some cases
    non-static data members and base class sub-objects are also value-initialized. 
    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 
 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 current C++ Standard states that '()' invokes default-initialization,
not value-initialization)</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);<br>int x ; // indeterminate initial value.<br>std::string s; // default-initialized.<br>eat ( int() ) ; // value-initialized<br>eat ( std::string() ) ; // value-initialied</pre>
                    
<h4><a name="valueinitsyn">value-initialization</a> syntax</h4>
                   
<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>
                   
<pre>int x() ; // declares function int(*)()<br>int y ( int() ) ; // decalares function int(*)( int(*)() )</pre>
                    
<p>Thus, the empty () must be put in some other initialization context.</p>
                   
<p>One alternative is to use copy-initialization syntax:</p>
                   
<pre>int x = int() ;</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,
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>One possible generic solution is to use value-initialization of a non static
data member:</p>
                   
<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>
                    
<p><code>This is the solution supplied by the value_initialized&lt;&gt; template
     class.</code></p>
                   
<h2><a name="types"></a>Types</h2>
                   
<h2><a name="val_init"><code>template class value_initialized&lt;T&gt;</code></a></h2>
                   
<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>unspecified</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>
                    
<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>) 
    is <a href="#valueinit">value-initialized</a> upon default-initialization 
    of this wrapper class: </p>
                   
<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>
                    
<p>The purpose of this wrapper is to provide a consistent syntax for value
     initialization of scalar, union and class types (POD and non-POD) since
   the  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
     <code>T&amp;</code>, the member function <code>data()</code>, or the
non-member    function <code>get()</code>:  </p>
                   
<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>
                    
<p>Both <code>const</code> and non-<code>const</code> objects can be wrapped. 
    Mutable objects can be modified directly from within the wrapper but constant
    objects cannot:</p>
                   
<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>
                    
<h3>Warning:</h3>
                   
<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 Bjrn 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>