[12] | 1 | <html> |
---|
| 2 | <head> |
---|
| 3 | |
---|
| 4 | <meta http-equiv="Content-Type" |
---|
| 5 | content="text/html; charset=iso-8859-1"> |
---|
| 6 | <title>value_initialized</title> |
---|
| 7 | |
---|
| 8 | </head> |
---|
| 9 | <body vlink="#800080" link="#0000ff" text="#000000" bgcolor="#ffffff"> |
---|
| 10 | |
---|
| 11 | <h2><img src="../../boost.png" width="276" height="86"> |
---|
| 12 | Header <<a href="../../boost/utility/value_init.hpp">boost/utility/value_init.hpp</a>> |
---|
| 13 | </h2> |
---|
| 14 | |
---|
| 15 | <h2>Contents</h2> |
---|
| 16 | |
---|
| 17 | <dl> |
---|
| 18 | <dt><a href="#rationale">Rationale</a></dt> |
---|
| 19 | <dt><a href="#intro">Introduction</a></dt> |
---|
| 20 | </dl> |
---|
| 21 | |
---|
| 22 | <ul> |
---|
| 23 | <li><a href="#valueinit">value-initialization</a></li> |
---|
| 24 | <li><a href="#valueinitsyn">value-initialization syntax</a></li> |
---|
| 25 | |
---|
| 26 | </ul> |
---|
| 27 | |
---|
| 28 | <dl class="page-index"> |
---|
| 29 | <dt><a href="#types">Types</a></dt> |
---|
| 30 | </dl> |
---|
| 31 | |
---|
| 32 | <ul> |
---|
| 33 | <li><a href="#val_init"><code>value_initialized<></code></a></li> |
---|
| 34 | |
---|
| 35 | </ul> |
---|
| 36 | <a href="#acknowledgements">Acknowledgements</a><br> |
---|
| 37 | <br> |
---|
| 38 | |
---|
| 39 | <hr> |
---|
| 40 | <h2><a name="rationale"></a>Rationale</h2> |
---|
| 41 | |
---|
| 42 | <p>Constructing and initializing objects in a generic way is difficult in |
---|
| 43 | C++. The problem is that there are several different rules that apply |
---|
| 44 | for initialization. Depending on the type, the value of a newly constructed |
---|
| 45 | object can be zero-initialized (logically 0), default-constructed (using |
---|
| 46 | the default constructor), or indeterminate. When writing generic code, |
---|
| 47 | this problem must be addressed. <code>value_initialized</code> provides |
---|
| 48 | a solution with consistent syntax for value initialization of scalar, |
---|
| 49 | union and class types. <br> |
---|
| 50 | </p> |
---|
| 51 | |
---|
| 52 | <h2><a name="intro"></a>Introduction</h2> |
---|
| 53 | |
---|
| 54 | <p>The C++ standard [<a href="#references">1</a>] contains the definitions |
---|
| 55 | of <code>zero-initialization</code> and <code>default-initialization</code>. |
---|
| 56 | Informally, zero-initialization means that the object is given the initial |
---|
| 57 | value 0 (converted to the type) and default-initialization means that |
---|
| 58 | POD [<a href="#references">2</a>] types are zero-initialized, while class |
---|
| 59 | types are initialized with their corresponding default constructors. A |
---|
| 60 | <i>declaration</i> can contain an <i>initializer</i>, which specifies the |
---|
| 61 | object's initial value. The initializer can be just '()', which states that |
---|
| 62 | the object shall be default-initialized (but see below). However, if a <i>declaration</i> |
---|
| 63 | has no <i>initializer</i> and it is of a non-<code>const</code>, non-<code>static</code> |
---|
| 64 | POD type, the initial value is indeterminate:<cite>(see §8.5 for the |
---|
| 65 | accurate definitions).</cite></p> |
---|
| 66 | |
---|
| 67 | <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> |
---|
| 68 | |
---|
| 69 | <h3><a name="valueinit">value-initialization</a></h3> |
---|
| 70 | |
---|
| 71 | <p>The first <a |
---|
| 72 | href="http://anubis.dkuug.dk/JTC1/SC22/WG21/docs/cwg_defects.html">Technical |
---|
| 73 | Corrigendum for the C++ Standard</a> (TC1), whose draft was released to |
---|
| 74 | the public in November 2001, introduced <a |
---|
| 75 | href="http://anubis.dkuug.dk/JTC1/SC22/WG21/docs/cwg_defects.html#178">Core |
---|
| 76 | Issue 178</a> (among many other issues, of course).</p> |
---|
| 77 | |
---|
| 78 | <p> That issue introduced the new concept of <code>value-initialization</code> |
---|
| 79 | (it also fixed the wording for zero-initialization). Informally, value-initialization |
---|
| 80 | is similar to default-initialization with the exception that in some cases |
---|
| 81 | non-static data members and base class sub-objects are also value-initialized. |
---|
| 82 | The difference is that an object that is value-initialized won't have |
---|
| 83 | (or at least is less likely to have) indeterminate values for data members |
---|
| 84 | and base class sub-objects; unlike the case of an object default constructed. |
---|
| 85 | (see Core Issue 178 for a normative description).</p> |
---|
| 86 | |
---|
| 87 | <p>In order to specify value-initialization of an object we need to use the |
---|
| 88 | empty-set initializer: (). </p> |
---|
| 89 | |
---|
| 90 | <p><i>(but recall that the current C++ Standard states that '()' invokes default-initialization, |
---|
| 91 | not value-initialization)</i></p> |
---|
| 92 | |
---|
| 93 | <p>As before, a declaration with no intializer specifies default-initialization, |
---|
| 94 | and a declaration with a non-empty initializer specifies copy (=xxx) or |
---|
| 95 | direct (xxx) initialization. </p> |
---|
| 96 | |
---|
| 97 | <pre>template<class T> 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> |
---|
| 98 | |
---|
| 99 | <h4><a name="valueinitsyn">value-initialization</a> syntax</h4> |
---|
| 100 | |
---|
| 101 | <p>Value initialization is specified using (). However, the empty set of |
---|
| 102 | parentheses is not permitted by the syntax of initializers because it is |
---|
| 103 | parsed as the declaration of a function taking no arguments: </p> |
---|
| 104 | |
---|
| 105 | <pre>int x() ; // declares function int(*)()<br>int y ( int() ) ; // decalares function int(*)( int(*)() )</pre> |
---|
| 106 | |
---|
| 107 | <p>Thus, the empty () must be put in some other initialization context.</p> |
---|
| 108 | |
---|
| 109 | <p>One alternative is to use copy-initialization syntax:</p> |
---|
| 110 | |
---|
| 111 | <pre>int x = int() ;</pre> |
---|
| 112 | |
---|
| 113 | <p>This works perfectly fine for POD types. But for non-POD class types, |
---|
| 114 | copy-initialization searches for a suitable constructor, which could be, |
---|
| 115 | for instance, the copy-constructor (it also searches for a suitable conversion |
---|
| 116 | sequence but this doesn't apply in this context). For an arbitrary unknown |
---|
| 117 | type, using this syntax may not have the value-initialization effect intended |
---|
| 118 | because we don't know if a copy from a default constructed object is exactly |
---|
| 119 | the same as a default constructed object, and the compiler is allowed (in |
---|
| 120 | some cases), but never required to, optimize the copy away.</p> |
---|
| 121 | |
---|
| 122 | <p>One possible generic solution is to use value-initialization of a non static |
---|
| 123 | data member:</p> |
---|
| 124 | |
---|
| 125 | <pre>template<class T> <br>struct W <br>{<br> // value-initialization of 'data' here.<br> W() : data() {}<br> T data ;<br>} ;<br>W<int> w ;<br>// w.data is value-initialized for any type. </pre> |
---|
| 126 | |
---|
| 127 | <p><code>This is the solution supplied by the value_initialized<> template |
---|
| 128 | class.</code></p> |
---|
| 129 | |
---|
| 130 | <h2><a name="types"></a>Types</h2> |
---|
| 131 | |
---|
| 132 | <h2><a name="val_init"><code>template class value_initialized<T></code></a></h2> |
---|
| 133 | |
---|
| 134 | <pre>namespace boost {<br><br>template<class T><br>class value_initialized<br>{<br> public :<br> value_initialized() : x() {}<br> operator T&() const { return x ; }<br> T& data() const { return x ; }<br><br> private :<br> <i>unspecified</i> x ;<br>} ;<br><br>template<class T><br>T const& get ( value_initialized<T> const& x )<br>{<br> return x.data() ;<br>}<br><br>template<class T><br>T& get ( value_initialized<T>& x )<br>{<br> return x.data() ;<br>}<br><br>} // namespace boost<br></pre> |
---|
| 135 | |
---|
| 136 | <p>An object of this template class is a <code>T</code>-wrapper convertible |
---|
| 137 | to <code>'T&'</code> whose wrapped object (data member of type <code>T</code>) |
---|
| 138 | is <a href="#valueinit">value-initialized</a> upon default-initialization |
---|
| 139 | of this wrapper class: </p> |
---|
| 140 | |
---|
| 141 | <pre>int zero = 0 ;<br>value_initialized<int> x ;<br>assert ( x == zero ) ;<br><br>std::string def ;<br>value_initialized< std::string > y ;<br>assert ( y == def ) ;<br></pre> |
---|
| 142 | |
---|
| 143 | <p>The purpose of this wrapper is to provide a consistent syntax for value |
---|
| 144 | initialization of scalar, union and class types (POD and non-POD) since |
---|
| 145 | the correct syntax for value initialization varies (see <a |
---|
| 146 | href="#valueinitsyn">value-initialization syntax</a>)</p> |
---|
| 147 | |
---|
| 148 | <p>The wrapped object can be accessed either through the conversion operator |
---|
| 149 | <code>T&</code>, the member function <code>data()</code>, or the |
---|
| 150 | non-member function <code>get()</code>: </p> |
---|
| 151 | |
---|
| 152 | <pre>void watch(int);<br>value_initialized<int> x;<br><br>watch(x) ; // operator T& used.<br>watch(x.data());<br>watch( get(x) ) // function get() used</pre> |
---|
| 153 | |
---|
| 154 | <p>Both <code>const</code> and non-<code>const</code> objects can be wrapped. |
---|
| 155 | Mutable objects can be modified directly from within the wrapper but constant |
---|
| 156 | objects cannot:</p> |
---|
| 157 | |
---|
| 158 | <pre>value_initialized<int> x ; <br>static_cast<int&>(x) = 1 ; // OK<br>get(x) = 1 ; // OK<br><br>value_initialized<int const> y ; <br>static_cast<int&>(y) = 1 ; // ERROR: cannot cast to int&<br>static_cast<int const&>(y) = 1 ; // ERROR: cannot modify a const value<br>get(y) = 1 ; // ERROR: cannot modify a const value</pre> |
---|
| 159 | |
---|
| 160 | <h3>Warning:</h3> |
---|
| 161 | |
---|
| 162 | <p>Both the conversion operator and the <code>data()</code> member function |
---|
| 163 | are <code>const</code> in order to allow access to the wrapped object |
---|
| 164 | from a constant wrapper:</p> |
---|
| 165 | |
---|
| 166 | <pre>void foo(int);<br>value_initialized<int> const x ;<br>foo(x);<br></pre> |
---|
| 167 | |
---|
| 168 | <p>But notice that this conversion operator is to <code>T&</code> although |
---|
| 169 | it is itself <code>const</code>. As a consequence, if <code>T</code> is |
---|
| 170 | a non-<code>const</code> type, you can modify the wrapped object even from |
---|
| 171 | within a constant wrapper:</p> |
---|
| 172 | |
---|
| 173 | <pre>value_initialized<int> const x_c ;<br>int& xr = x_c ; // OK, conversion to int& available even though x_c is itself const.<br>xr = 2 ; </pre> |
---|
| 174 | |
---|
| 175 | <p>The reason for this obscure behavior is that some commonly used compilers |
---|
| 176 | just don't accept the following valid code:</p> |
---|
| 177 | |
---|
| 178 | <pre>struct X<br>{<br> operator int&() ;<br> operator int const&() const ; <br>};<br>X x ;<br>(x == 1 ) ; // ERROR HERE!</pre> |
---|
| 179 | |
---|
| 180 | <p>These compilers complain about ambiguity between the conversion operators. |
---|
| 181 | This complaint is incorrect, but the only workaround that I know of is |
---|
| 182 | to provide only one of them, which leads to the obscure behavior just explained.<br> |
---|
| 183 | </p> |
---|
| 184 | |
---|
| 185 | <h3>Recommended practice: The non-member get() idiom</h3> |
---|
| 186 | |
---|
| 187 | <p>The obscure behavior of being able to modify a non-<code>const</code> |
---|
| 188 | wrapped object from within a constant wrapper can be avoided if access to |
---|
| 189 | the wrapped object is always performed with the <code>get()</code> idiom:</p> |
---|
| 190 | |
---|
| 191 | <pre>value_initialized<int> x ;<br>get(x) = 1 ; // OK<br><br>value_initialized<int const> cx ;<br>get(x) = 1 ; // ERROR: Cannot modify a const object<br><br>value_initialized<int> const x_c ;<br>get(x_c) = 1 ; // ERROR: Cannot modify a const object<br><br>value_initialized<int const> const cx_c ;<br>get(cx_c) = 1 ; // ERROR: Cannot modify a const object<br></pre> |
---|
| 192 | |
---|
| 193 | <h3><a name="references">References</a></h3> |
---|
| 194 | [1] The C++ Standard, ISO/IEC 14882:98 <br> |
---|
| 195 | [2] Plain Old Data |
---|
| 196 | <h3><a name="acknowledgements"></a>Acknowledgements</h3> |
---|
| 197 | value_initialized was developed by Fernando Cacciola, with help and |
---|
| 198 | suggestions from David Abrahams and Darin Adler.<br> |
---|
| 199 | Special thanks to Björn Karlsson who carefully edited and completed this documentation. |
---|
| 200 | <pre> </pre> |
---|
| 201 | |
---|
| 202 | <hr> |
---|
| 203 | <p>Revised 19 September 2002</p> |
---|
| 204 | |
---|
| 205 | <p>© Copyright boost.org 2002. Permission to copy, use, modify, sell |
---|
| 206 | and distribute this document is granted provided this copyright notice appears |
---|
| 207 | in all copies. This document is provided "as is" without express or implied |
---|
| 208 | warranty, and with no claim as to its suitability for any purpose.</p> |
---|
| 209 | |
---|
| 210 | <p>Developed by <a href="mailto:fernando_cacciola@hotmail.com">Fernando Cacciola</a>, |
---|
| 211 | the latest version of this file can be found at <a |
---|
| 212 | href="http://www.boost.org">www.boost.org</a>, and the boost discussion list |
---|
| 213 | at <a href="http://www.yahoogroups.com/list/boost">www.yahoogroups.com/list/boost</a>. |
---|
| 214 | </p> |
---|
| 215 | <br> |
---|
| 216 | <br> |
---|
| 217 | |
---|
| 218 | </body> |
---|
| 219 | </html> |
---|