|  | Home | Libraries | People | FAQ | More | 
          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. The template value_initialized provides a solution
          with consistent syntax for value initialization of scalar, union and class
          types. Moreover, value_initialized offers a workaround
          to various compiler issues regarding value-initialization.
        
          Furthermore, a const object
          initialized_value
          is provided, to avoid repeating the type name when retrieving the value
          from a value_initialized<T>
There are various ways to initialize a variable, in C++. The following declarations all may have a local variable initialized to its default value:
T1 var1; T2 var2 = 0; T3 var3 = {}; T4 var4 = T4();
Unfortunately, whether or not any of those declarations correctly initialize the variable very much depends on its type. The first declaration is valid for any DefaultConstructible type by definition.
          However, it does not always do an initialization. It correctly initializes
          the variable when it's an instance of a class, and the author of the class
          has provided a proper default constructor. On the other hand, the value
          of var1 is indeterminate
          when its type is an arithmetic type, like int,
          float, or char.
        
          An arithmetic variable is of course initialized properly by the second
          declaration, T2 var2
          = 0.
          But this initialization form will not usually work for a class type, unless
          the class was especially written to support being initialized that way.
        
          The third form, T3 var3
          = {},
          initializes an aggregate, typically a "C-style" struct or a "C-style" array. However,
          at the time this library was developed, the syntax did not allow for a
          class that has an explicitly declared constructor.
        
          The fourth form is the most generic form of them, as it can be used to
          initialize arithmetic types, class types, aggregates, pointers, and other
          types. The declaration, T4 var4 = T4(),
          should be read as follows: First a temporary object is created, by T4().
          This object is value-initialized.
          Next the temporary object is copied to the named variable, var4. Afterwards, the temporary is destroyed.
          While the copying and the destruction are likely to be optimized away,
          C++ still requires the type T4
          to be CopyConstructible.
          So T4 needs to be both
          DefaultConstructible
          and CopyConstructible.
        
          A class may not be CopyConstructible, for example because it may have a
          private and undefined copy constructor, or because it may be derived from
          boost::noncopyable. Scott Meyers [2]
          explains why a class would be defined like that.
        
          There is another, less obvious disadvantage to the fourth form, T4 var4
          = T4(): It suffers from various compiler
          issues, causing a variable to be left uninitialized in some compiler
          specific cases.
        
          The template value_initialized
          offers a generic way to initialize an object, like T4
          var4 =
          T4(),
          but without requiring its type to be CopyConstructible.
          And it offers a workaround to those compiler issues regarding value-initialization
          as well. It allows getting an initialized variable of any type; it only
          requires the type to be DefaultConstructible.
          A properly value-initialized object of type T is constructed by the following declaration:
        
value_initialized<T> var;
          The template initialized
          offers both value-initialization and direct-initialization. It is especially
          useful as a data member type, allowing the very same object to be either
          direct-initialized or value-initialized.
        
          The const object initialized_value allows value-initializing
          a variable as follows:
        
T var = initialized_value;
          This form of initialization is semantically equivalent to T4 var4
          = T4(), but robust against the aforementioned
          compiler issues.
        
          The C++ standard [3] contains the
          definitions of zero-initialization and default-initialization.
          Informally, zero-initialization means that the object is given the initial
          value 0 converted to the type
          and default-initialization means that POD [4]
          types are zero-initialized, while non-POD class types are initialized with
          their corresponding default constructors.
        
          A declaration can contain an initializer,
          which specifies the object's initial value. The initializer can be just
          '()', which states that the object shall be value-initialized (but see
          below). However, if a declaration has no initializer
          and it is of a non-const,
          non-static POD type, the initial
          value is indeterminate: (see §8.5, [dcl.init], for the accurate
          definitions).
        
int x; // no initializer. x value is indeterminate.std::strings; // 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 ()
The first Technical Corrigendum for the C++ Standard (TC1), whose draft was released to the public in November 2001, introduced Core Issue 178, among many other issues.
          That issue introduced the new concept of value-initialization,
          and 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 will not 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).
          In order to specify value-initialization of an object we need to use the
          empty-set initializer: ().
        
          As before, a declaration with no initializer specifies default-initialization,
          and a declaration with a non-empty initializer specifies copy (=xxx)
          or direct (xxx) initialization.
        
template<class T> void eat(T); int x ; // indeterminate initial value.std::strings; // default-initialized. eat ( int() ) ; // value-initialized eat (std::string() ) ; // value-initialized
          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:
        
int x() ; // declares function int(*)()
          Thus, the empty () must be
          put in some other initialization context.
        
One alternative is to use copy-initialization syntax:
int x = int();
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 does not 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.
One possible generic solution is to use value-initialization of a non static data member:
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.
          This is the solution as it was supplied by earlier versions of the value_initialized<T>
Various compilers have not yet fully implemented value-initialization. So when an object should be value-initialized according to the C++ Standard, it may in practice still be left uninitialized, because of those compiler issues. It is hard to make a general statement on what those issues are like, because they depend on the compiler you are using, its version number, and the type of object you would like to have value-initialized.
All compilers we have tested so far support value-initialization for arithmetic types properly. However, various compilers may leave some types of aggregates uninitialized, when they should be value-initialized. Value-initialization of objects of a pointer-to-member type may also go wrong on various compilers.
At the moment of writing, May 2010, the following reported issues regarding value-initialization are still there in current compiler releases:
Note that all known GCC issues regarding value-initialization are fixed with GCC version 4.4, including GCC Bug 30111. Clang also has completely implemented value-initialization, as far as we know, now that Clang Bug 7139 is fixed.
          New versions of value_initialized
          (Boost release version 1.35 or higher) offer a workaround to these issues:
          value_initialized
          may now clear its internal data, prior to constructing the object that
          it contains. It will do so for those compilers that need to have such a
          workaround, based on the compiler
          defect macro BOOST_NO_COMPLETE_VALUE_INITIALIZATION.
        
namespace boost { template<class T> classvalue_initialized{ public :value_initialized() : x() {} operator T const &() const { return x ; } operator T&() { return x ; } T const &data() const { return x ; } T& data() { return x ; } void swap(value_initialized& ); private : [unspecified] 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(); } template<class T> void swap (value_initialized<T>& lhs,value_initialized<T>& rhs ) { lhs.swap(rhs); } } // namespace boost
            An object of this template class is a T-wrapper
            convertible to 'T&' whose
            wrapped object (data member of type T)
            is value-initialized upon default-initialization
            of this wrapper class:
          
int zero = 0;value_initialized<int> x; assert( x == zero ) ;std::stringdef;value_initialized<std::string> y; assert( y == def ) ;
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 value-initialization syntax).
            The wrapped object can be accessed either through the conversion operator
            T&,
            the member function data(), or the non-member function get():
          
void watch(int);
value_initialized<int> x;
watch(x) ; // operator T& used.
watch(x.data());
watch( get(x) ) // function get() used
            Both const and non-const objects can be wrapped. Mutable
            objects can be modified directly from within the wrapper but constant
            objects cannot:
          
            When T is a Swappable
            type, value_initialized<T>swap member function
            as well as by calling boost::swap.
          
value_initialized<int> x; static_cast<int&>(x) = 1 ; // OK get(x) = 1 ; // OKvalue_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
| ![[Warning]](../../../../../../doc/src/images/warning.png) | Warning | 
|---|---|
| 
              The  For example: The reason for this obscure behavior was that some compilers did not accept the following valid code: struct X { operator int&() ; operator int const&() const ; }; X x ; (x == 1) ; // ERROR HERE! 
              The current version of  | 
            The obscure behavior of being able to modify a non-const
            wrapped object from within a constant wrapper (as was supported by previous
            versions of value_initialized)
            can be avoided if access to the wrapped object is always performed with
            the get()
            idiom:
          
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
namespace boost { template<class T> classinitialized{ public :initialized() : x() {} explicitinitialized(T const & arg) : x(arg) {} operator T const &() const; operator T&(); T const &data() const; T& data(); void swap(initialized& ); private : [unspecified] x ; }; template<class T> T const& get (initialized<T> const& x ); template<class T> T& get (initialized<T>& x ); template<class T> void swap (initialized<T>& lhs,initialized<T>& rhs ); } // namespace boost
            The template class boost::
            supports both value-initialization and direct-initialization, so its
            interface is a superset of the interface of initialized<T>value_initialized<T>value_initialized<T>boost:: also offers an extra initialized<T>explicit constructor, which direct-initializes
            the wrapped object by the specified value.
          
            initialized<T>initialized<T>
            On the other hand, if it is known beforehand that the object must always
            be value-initialized, value_initialized<T>
namespace boost { classinitialized_value_t{ public : template <class T> operator T() const ; };initialized_value_tconst initialized_value = {} ; } // namespace boost
            initialized_value
            provides a convenient way to get an initialized value: its conversion
            operator provides an appropriate value-initialized
            object for any CopyConstructible
            type.
          
            Suppose you need to have an initialized variable of type T. You could do it as follows:
          
T var = T();
            But as mentioned before, this form suffers from various compiler issues.
            The template value_initialized
            offers a workaround:
          
T var = get( value_initialized<T>() );
            Unfortunately both forms repeat the type name, which is rather short
            now (T), but could of
            course be more like Namespace::Template<Arg>::Type.
          
            Instead, one could use initialized_value as follows:
          
T var = initialized_value;
var of any DefaultConstructible
              type T to be value-initialized
              by doing T var
              = {}.
              The papers are listed at Bjarne's web page, My
              C++ Standards committee papers.
            
          value_initialized
          was developed by Fernando Cacciola, with help and suggestions from David
          Abrahams and Darin Adler.
        
Special thanks to Bjorn Karlsson who carefully edited and completed this documentation.
          value_initialized
          was reimplemented by Fernando Cacciola and Niels Dekker for Boost release
          version 1.35 (2008), offering a workaround to various compiler issues.
        
          boost::
          was very much inspired by feedback from Edward Diener and Jeffrey Hellrung.
        initialized
          initialized_value
          was written by Niels Dekker, and added to Boost release version 1.36 (2008).
        
Developed by Fernando Cacciola. The latest version of this file can be found at www.boost.org.