File: value_init.qbk

package info (click to toggle)
boost1.90 1.90.0-5
  • links: PTS, VCS
  • area: main
  • in suites: forky
  • size: 593,168 kB
  • sloc: cpp: 4,190,642; xml: 196,648; python: 34,618; ansic: 23,145; asm: 5,468; sh: 3,776; makefile: 1,162; perl: 1,020; sql: 728; ruby: 676; yacc: 478; java: 77; lisp: 24; csh: 6
file content (578 lines) | stat: -rw-r--r-- 20,932 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
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
[/
 / Copyright (c) 2012 Marshall Clow
 / Copyright (c) 2021, Alan Freitas
 /
 / Distributed under the Boost Software License, Version 1.0. (See accompanying
 / file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 /]

[/===============]
[section:value_init Value Init]
[/===============]

[section Introduction]

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>` object.

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 [link utility.utilities.value_init.details.value_initialization 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 \[[link utility.utilities.value_init.references 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 [link utility.utilities.value_init.details.compiler_issues 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.

[endsect]

[section:details Details]

The C++ standard \[[link utility.utilities.value_init.references 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 [@https://en.cppreference.com/w/cpp/named_req/PODType POD] \[[link utility.utilities.value_init.references 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 [sect]8.5, \[dcl.init\], for the
accurate definitions).

```
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 ()
```

[section:value_initialization value-initialization]

The first [@http://www.open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html Technical
Corrigendum for the C++ Standard] (TC1), whose draft was released to the public in
November 2001, introduced [@http://www.open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html#178 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_string__ s; // default-initialized.

eat ( int() ) ; // value-initialized

eat ( __std_string__() ) ; // value-initialized
```

[endsect]

[section:syntax value-initialization syntax]

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>` template class. Unfortunately this approach
suffered from various compiler issues.

[endsect]

[section:compiler_issues Compiler issues]

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:

* [@https://connect.microsoft.com/VisualStudio/feedback/details/100744 Microsoft Visual Studio Feedback ID 100744, Value-initialization in new-expression]: Reported by Pavel Kuznetsov (MetaCommunications Engineering), 2005.
* [@http://connect.microsoft.com/VisualStudio/feedback/details/484295 Microsoft Visual Studio Feedback ID 484295, VC++ does not value-initialize members of derived classes without user-declared constructor] Reported by Sylvester Hesp, 2009.
* [@https://connect.microsoft.com/VisualStudio/feedback/details/499606 Microsoft Visual Studio Feedback ID 499606, Presence of copy constructor breaks member class initialization] Reported by Alex Vakulenko, 2009
* [@http://qc.embarcadero.com/wc/qcmain.aspx?d=83751 Embarcadero/C++Builder Report 83751, Value-initialization: arrays should have each element value-initialized] Reported by Niels Dekker (LKEB), 2010.
* [@http://qc.embarcadero.com/wc/qcmain.aspx?d=83851 Embarcadero/C++Builder Report 83851, Value-initialized temporary triggers internal backend error C1798] Reported by Niels Dekker, 2010.
* [@http://qc.embarcadero.com/wc/qcmain.aspx?d=84279 Embarcadero/C++Builder Report 84279, Internal compiler error (F1004), value-initializing member function pointer by "new T()"] Reported by Niels Dekker, 2010
* Sun CR 6947016, Sun 5.10 may fail to value-initialize an object of a non-POD aggregate. Reported to Steve Clamage by Niels Dekker, 2010.
* IBM's XL V10.1 and V11.1 may fail to value-initialize a temporary of a non-POD aggregate. Reported to Michael Wong by Niels Dekker, 2010.
* Intel support issue 589832, Attempt to value-initialize pointer-to-member triggers internal error on Intel 11.1. Reported by John Maddock, 2010.

Note that all known GCC issues regarding value-initialization are fixed with GCC version 4.4, including
[@http://gcc.gnu.org/bugzilla/show_bug.cgi?id=30111 GCC Bug 30111]. Clang also has completely implemented
value-initialization, as far as we know, now that [@http://llvm.org/bugs/show_bug.cgi?id=7139 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
[@boost:/libs/config/doc/html/boost_config/boost_macro_reference.html#boost_config.boost_macro_reference.macros_that_describe_defects
compiler defect macro] `BOOST_NO_COMPLETE_VALUE_INITIALIZATION`.

[endsect]

[endsect]

[section:types Types and objects]

[section:val_init `template class value_initialized<T>`]

```
namespace boost {

template<class T>
class __value_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 [link utility.utilities.value_init.details.value_initialization value-initialized] upon default-initialization
of this wrapper class:

```
int zero = 0;
__value_initialized__<int> x;
assert( x == zero ) ;

__std_string__ def;
__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 [link utility.utilities.value_init.details.syntax 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>`
is swappable as well, by calling its `swap` member function
as well as by calling `boost::swap`.

```
__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
```

[warning

The __value_initialized__ implementation of Boost version 1.40.0 and older
allowed ['non-const] access to the wrapped object, from a constant wrapper,
both by its conversion operator and its `data()` member function.

For example:

```
__value_initialized__<int> const x_c;
int& xr = x_c ; // OK, conversion to int& available even though x_c is itself const.
xr = 2 ;
```

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 __value_initialized__ no longer has this obscure behavior.
As compilers nowadays widely support overloading the conversion operator by having a `const`
and a `non-const` version, we have decided to fix the issue accordingly. So the current version
supports the idea of logical constness.

]

[section Recommended practice: The non-member get() idiom]

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
```

[endsect]

[endsect]

[section:initialized `template class initialized<T>`]


```
namespace boost {

template<class T>
class __initialized__
{

  public :

    __initialized__() : x() {}

    explicit __initialized__(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::__initialized__<T>` supports both value-initialization
and direct-initialization, so its interface is a superset of the interface
of `__value_initialized__<T>`: Its default-constructor value-initializes the
wrapped object just like the default-constructor of `__value_initialized__<T>`,
but `boost::__initialized__<T>` also offers an extra `explicit`
constructor, which direct-initializes the wrapped object by the specified value.

`__initialized__<T>` is especially useful when the wrapped
object must be either value-initialized or direct-initialized, depending on
runtime conditions. For example, `__initialized__<T>` could
hold the value of a data member that may be value-initialized by some
constructors, and direct-initialized by others.

On the other hand, if it is known beforehand that the
object must ['always] be value-initialized, `__value_initialized__<T>`
may be preferable. And if the object must always be
direct-initialized, none of the two wrappers really needs to be used.

[endsect]

[section:initialized_value `initialized_value`]

```
namespace boost {
class __initialized_value_t__
{
  public :
    template <class T> operator T() const ;
};

__initialized_value_t__ const 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__;
```

[endsect]
[endsect]

[section:references References]

# Bjarne Stroustrup, Gabriel Dos Reis, and J. Stephen Adamczyk wrote various papers,
proposing to extend the support for brace-enclosed ['initializer lists]
in C++. This [@https://en.cppreference.com/w/cpp/language/list_initialization feature] has
now been available since C++11. This would allow a variable `var` of any __DefaultConstructible__ type
`T` to be ['value-initialized] by doing `T var = {}`. The papers are listed at Bjarne's web page,
[@http://www.research.att.com/~bs/WG21.html My C++ Standards committee papers].

# Scott Meyers, Effective C++, Third Edition, item 6, ['Explicitly disallow the use of
compiler-generated functions you do not want], [@http://www.aristeia.com/books.html Scott Meyers: Books and CDs]

# The C++ Standard, Second edition (2003), ISO/IEC 14882:2003

# POD stands for [@https://en.cppreference.com/w/cpp/named_req/PODType "Plain Old Data"]

[endsect]

[/===============]
[xinclude tmp/value_init_reference.xml]
[/===============]

[section:acknowledgements Acknowledgements]

__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::__initialized__` was very much inspired by feedback from Edward Diener and Jeffrey Hellrung.

__initialized_value__ was written by Niels Dekker, and added to Boost release version 1.36 (2008).

Developed by [@mailto:fernando_cacciola@hotmail.com Fernando Cacciola]. The latest version of
this file can be found at [@http://www.boost.org www.boost.org].

[endsect]

[endsect]