![](/style/images/good.png)
![](/style/images/bad.png)
PSA: Value-initialization is not merely default-construction
source link: https://quuxplusone.github.io/blog/2023/06/22/psa-value-initialization/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
PSA: Value-initialization is not merely default-construction
At the Varna WG21 meeting, Giuseppe D’Angelo presented his
P2782 “Type trait to detect if value initialization can be achieved by zero-filling”.
The intent of this new type trait is to tell vector
’s implementor
whether
std::vector<T> v;
v.resize(1000);
can just do a memset
of all the T
objects to put them into their correctly
constructed state. By “correctly constructed state,” I mean the state a T
would
be in after
::new (p) T(); // value-initialization
The syntax T()
causes
a kind of initialization called value-initialization.
Here’s a public service announcement (not for Giuseppe, who knows;
but perhaps for you, dear reader; and probably for me again six months from now) —
Value-initialization is not merely default-construction!
Value-initialization for a type with a defaulted default constructor does zero-initialization first, then calls the default constructor. The effects are most visible for primitive scalar types:
int i; // default-initialized, garbage value
int j = int(); // value-initialized, always zero
int
is both trivially default-constructible (because you can default-initialize
an int
by default-initializing each of the unsigned chars in its
object representation to garbage),
and trivially value-initializable (because you can value-initialize an int
by
value-initializing each of the unsigned chars in its object representation to zero).
Yet “trivially default-constructible” and “trivially value-initializable” are 100% orthogonal properties. Here’s a constructive proof:
struct T;
struct S1 {
explicit S1() = default;
int T::*mf;
};
struct S2 {
explicit S2() {}
int T::*mf;
};
Struct S1
is trivially default-constructible, but it is not trivially value-initializable.
Struct S2
is trivially value-initializable, but it is not trivially default-constructible.
We prove our assertion about trivial value-initializability by by writing a little function and seeing how the compiler optimizes it.
S1 f1() { return S1(); }
S2 f2() { return S2(); }
clang++ -O2
produces:
_Z2f1v:
movq $-1, %rax
retq
_Z2f2v:
retq
The object representation of a value-initialized S1()
is all-bits-one, but the object representation
of a value-initialized S2()
is not just all-bits-zero — it’s actually indeterminate! We might call that
“even better than trivial.”
To focus on “better than triviality” would be a mistake: only contrived types like
S2
partake of it. In fact we would expect__is_trivially_value_initializable(S2)
to reportfalse
in practice, becauseS2
’s default constructor is user-provided and thus not readily inspectable by the front-end. Its triviality is discovered only by the optimizer.
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK