mirror of
				https://github.com/boostorg/utility.git
				synced 2025-11-04 02:11:45 +01:00 
			
		
		
		
	Compare commits
	
		
			2 Commits
		
	
	
		
			svn-branch
			...
			svn-branch
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					7c9c9c9a1c | ||
| 
						 | 
					b0b821c0d1 | 
							
								
								
									
										474
									
								
								value_init.htm
									
									
									
									
									
								
							
							
						
						
									
										474
									
								
								value_init.htm
									
									
									
									
									
								
							@@ -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>
 | 
			
		||||
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> 
 | 
			
		||||
<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">Header <<A
 | 
			
		||||
HREF="../../boost/utility/aligned_storage.hpp">boost/utility/value_init.hpp</A>>
 | 
			
		||||
</H2>
 | 
			
		||||
<H2>Contents</H2>
 | 
			
		||||
<DL>
 | 
			
		||||
<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<></CODE></A></LI>
 | 
			
		||||
</UL>
 | 
			
		||||
<HR>
 | 
			
		||||
<H2><A NAME="into"></A>Introduction</H2>
 | 
			
		||||
<P>The C++ standard document realeased by 1998 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 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 determines 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-const non-static POD type, the initial value is indeterminate:<CITE>(see
 | 
			
		||||
8.5 for the accurate definitions)</CITE></P>
 | 
			
		||||
<PRE>int x ; // no initializer. x value is indeterminate.
 | 
			
		||||
std::string s ; // no initializer, s is default-constructed.
 | 
			
		||||
 | 
			
		||||
int y = int() ; 
 | 
			
		||||
// 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 ) ;
 | 
			
		||||
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 Technical Corrigendum for the C++ Standard (TC1), whose darft was
 | 
			
		||||
released to the public on Nov, 2001, introduced Core Issue 178 (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 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<class T> 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>Value initialization is specified using (). However, the empty set of
 | 
			
		||||
parentheses is not permited by the syntax of the initializer because it is
 | 
			
		||||
parsed as the declaration of a function taking no arguments: </P>
 | 
			
		||||
<PRE>int x() ; // declares function int(*)()
 | 
			
		||||
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 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<class T> 
 | 
			
		||||
struct W 
 | 
			
		||||
{
 | 
			
		||||
        // value-initialization of 'data' here.
 | 
			
		||||
  W() : data() {}
 | 
			
		||||
  T data ;
 | 
			
		||||
} ;
 | 
			
		||||
W<int> w ;
 | 
			
		||||
// w.data is value-initialized for any type. </PRE>
 | 
			
		||||
 | 
			
		||||
<P>This is the solution supplied by the value_initialized<> template
 | 
			
		||||
class.</P>
 | 
			
		||||
<H2><A NAME="types"></A>Types</H2>
 | 
			
		||||
<H2><A NAME="val_init"><CODE>template class
 | 
			
		||||
value_initialized<T></CODE></A></H2>
 | 
			
		||||
<PRE>namespace boost {
 | 
			
		||||
 | 
			
		||||
template<class T>
 | 
			
		||||
class value_initialized
 | 
			
		||||
{
 | 
			
		||||
  public :
 | 
			
		||||
 | 
			
		||||
    value_initialized() : x() {}
 | 
			
		||||
 | 
			
		||||
    operator T&() const { return x ; }
 | 
			
		||||
 | 
			
		||||
    T& data() const { return x ; }
 | 
			
		||||
 | 
			
		||||
  private :
 | 
			
		||||
 | 
			
		||||
    <I>impll-defined</I> x ;
 | 
			
		||||
} ;
 | 
			
		||||
 | 
			
		||||
template<class T>
 | 
			
		||||
T const& get ( value_initialized<T> const& x )
 | 
			
		||||
{
 | 
			
		||||
  return x.data() ;
 | 
			
		||||
}
 | 
			
		||||
template<class T>
 | 
			
		||||
T& get ( value_initialized<T>& x )
 | 
			
		||||
{
 | 
			
		||||
  return x.data() ;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace boost
 | 
			
		||||
</PRE>
 | 
			
		||||
 | 
			
		||||
<P>An object of this template class is a T-wrapper convertible to
 | 
			
		||||
<CODE>'T&'</CODE> whose wrapped object (data member of type T) is
 | 
			
		||||
<A HREF="#valueinit">value-initialized</A> upon default-initialization of this
 | 
			
		||||
wrapper class: </P>
 | 
			
		||||
<PRE>
 | 
			
		||||
int zero = 0 ;
 | 
			
		||||
value_initialized<int> x ;
 | 
			
		||||
assert ( x == zero ) ;
 | 
			
		||||
 | 
			
		||||
std::string def ;
 | 
			
		||||
value_initialized< std::string > y ;
 | 
			
		||||
assert ( y == def ) ;
 | 
			
		||||
</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
 | 
			
		||||
T&, the member function data(), or the non-member friend function get(): 
 | 
			
		||||
</P>
 | 
			
		||||
<PRE>void watch(int);
 | 
			
		||||
value_initialized<int> x;
 | 
			
		||||
 | 
			
		||||
watch(x) ; // operator T& used.
 | 
			
		||||
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
 | 
			
		||||
objects can be modified directly from within the wrapper but constant objects
 | 
			
		||||
cannot:</P>
 | 
			
		||||
<PRE>value_initialized<int> x ; 
 | 
			
		||||
static_cast<int&>(x) = 1 ; // OK
 | 
			
		||||
get(x) = 1 ; // OK
 | 
			
		||||
 | 
			
		||||
value_initialized<int const> y ; 
 | 
			
		||||
static_cast<int&>(y) = 1 ; // ERROR: cannot cast to int&
 | 
			
		||||
static_cast<int const&>(y) = 1 ; // ERROR: cannot modify a const value
 | 
			
		||||
get(y) = 1 ; // ERROR: cannot modify a const value</PRE>
 | 
			
		||||
 | 
			
		||||
<H3>warning:</H3>
 | 
			
		||||
<BLOCKQUOTE> <P>Both the conversion operator and the data() member function are
 | 
			
		||||
<CODE>const</CODE> in order to allow access to the wrapped object from a
 | 
			
		||||
constant wrapper:</P>
 | 
			
		||||
<PRE>void foo(int);
 | 
			
		||||
value_initialized<int> const x ;
 | 
			
		||||
foo(x);
 | 
			
		||||
</PRE>
 | 
			
		||||
 | 
			
		||||
<P>But notice that this conversion operator is to <CODE>T&</CODE> but it is
 | 
			
		||||
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<int> const x_c ;
 | 
			
		||||
int& xr = x_c ; // OK, conversion to int& available even though x_c is itself const.
 | 
			
		||||
xr = 2 ; </PRE>
 | 
			
		||||
 | 
			
		||||
<P>The reason for this obscure behaviour is that some commonly used compilers
 | 
			
		||||
just don't accept the following valid code:</P>
 | 
			
		||||
<PRE>
 | 
			
		||||
struct X
 | 
			
		||||
{
 | 
			
		||||
  operator int&() ;
 | 
			
		||||
  operator int const&() const ;   
 | 
			
		||||
};
 | 
			
		||||
X x ;
 | 
			
		||||
(x == 1 ) ; // ERROR HERE!</PRE>
 | 
			
		||||
 | 
			
		||||
<P>These compilers complain about ambiguity between the conversion operators. 
 | 
			
		||||
<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<int> x ;
 | 
			
		||||
get(x) = 1 ; // OK
 | 
			
		||||
 | 
			
		||||
value_initialized<int const> cx ;
 | 
			
		||||
get(x) = 1 ; // ERROR: Cannot modify a const object
 | 
			
		||||
 | 
			
		||||
value_initialized<int> const x_c ;
 | 
			
		||||
get(x_c) = 1 ; // ERROR: Cannot modify a const object
 | 
			
		||||
 | 
			
		||||
value_initialized<int const> const cx_c ;
 | 
			
		||||
get(cx_c) = 1 ; // ERROR: Cannot modify a const object
 | 
			
		||||
</PRE>
 | 
			
		||||
 | 
			
		||||
<HR>
 | 
			
		||||
<P>Revised 23 August 2002</P>
 | 
			
		||||
<P>© 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: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>
 | 
			
		||||
 | 
			
		||||
<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="../../c++boost.gif" width="276" height="86">
 | 
			
		||||
         Header <<a href="../../boost/utility/value_init.hpp">boost/utility/value_init.hpp</a>>
 | 
			
		||||
     </h2>
 | 
			
		||||
                   
 | 
			
		||||
<h2>Contents</h2>
 | 
			
		||||
                   
 | 
			
		||||
<dl>
 | 
			
		||||
  <dt><a href="#intro">Rationale</a></dt>
 | 
			
		||||
  <dt><a href="#rationale">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<></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
 | 
			
		||||
     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 §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<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>
 | 
			
		||||
                    
 | 
			
		||||
<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<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>
 | 
			
		||||
                    
 | 
			
		||||
<p><code>This is the solution supplied by the value_initialized<> template
 | 
			
		||||
     class.</code></p>
 | 
			
		||||
                   
 | 
			
		||||
<h2><a name="types"></a>Types</h2>
 | 
			
		||||
                   
 | 
			
		||||
<h2><a name="val_init"><code>template class value_initialized<T></code></a></h2>
 | 
			
		||||
                   
 | 
			
		||||
<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>impll-defined</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>
 | 
			
		||||
                    
 | 
			
		||||
<p>An object of this template class is a <code>T</code>-wrapper convertible 
 | 
			
		||||
    to <code>'T&'</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<int> x ;<br>assert ( x == zero ) ;<br><br>std::string def ;<br>value_initialized< std::string > 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&</code>, the member function <code>data()</code>, or the
 | 
			
		||||
non-member    function <code>get()</code>:  </p>
 | 
			
		||||
                   
 | 
			
		||||
<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>
 | 
			
		||||
                    
 | 
			
		||||
<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<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>
 | 
			
		||||
                    
 | 
			
		||||
<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<int> const x ;<br>foo(x);<br></pre>
 | 
			
		||||
                    
 | 
			
		||||
<p>But notice that this conversion operator is to <code>T&</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<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>
 | 
			
		||||
                    
 | 
			
		||||
<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&() ;<br>  operator int const&() 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<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>
 | 
			
		||||
                    
 | 
			
		||||
<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<42>rn Karlsson who carefully edited and completed this documentation.
 | 
			
		||||
<pre> </pre>
 | 
			
		||||
                    
 | 
			
		||||
<hr>          
 | 
			
		||||
<p>Revised 19 September 2002</p>
 | 
			
		||||
                   
 | 
			
		||||
<p>© 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>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user