Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When and how to default-initialize a const variable?

clang++ does not ever allow default initialization of a const variable of class-type without a user-defined constructor; g++ is slightly less restrictive (see below). According to this answer, this is because POD types "are not initialized by default." If I understand correctly, this means that default-initialization does not invoke the default-constructor, nor does it invoke value-initialization, so the data members inside the POD type are not initialized. Of course it makes no sense to have a const POD type with uninitialized values in it, since they can never be initialized and therefore are not safe to use.

There are a few variants of this situation:

  1. The type is technically "POD", but contains no data members (only functions). (clang++ does not treat this as a special case, nor, I think, does the standard, but g++ does allow it, even when the constructor is marked explicit.)
  2. An empty constructor is defined using {}. (This is the recommended workaround on the clang page describing the issue.)
  3. The default constructor is declared =default. (C++11 onward; the type is still considered POD, so neither compiler nor the standard treat it as a special case.)
  4. Aggregate initialization is explicitly invoked using {}, which (if I understand correctly) becomes value-initialization. (C++11 onward; both compilers—and, I think, the standard—allow this.)

In the first case, there can be no uninitialized members, so it's unclear why any instantiation of the class itself would ever be considered "uninitialized," regardless of whether or not it's const. Since g++ allows this behavior, is it safe to use? Why is it prohibited by clang++ and the standard? (And are there any other cases where g++ allows POD-default-initialization where clang++ does not?)

In the second and third cases, the requirement of using {} instead of =default seems odd to me. EDIT: this question explains the difference quite well, so I've removed the part of the question asking about the distinction. (I still think it's a terribly confusing aspect of the language, though.)

Finally, will Foo f{} always zero-initialize members of built-in type if Foo::Foo(void) is {}, =default, or implicitly-declared?

like image 414
Kyle Strand Avatar asked Jun 05 '15 03:06

Kyle Strand


1 Answers

Since g++ allows this behavior, is it safe to use?

Safe in what sense? It's obviously not portable currently. However, it's not going to give you unexpected results on g++.

Why is it prohibited by clang++ and the standard?

Presumably the committee either didn't think about it when they put the "user-provided constructor required" rule in C++98, or decided that special-casing empty POD classes isn't worth the specification complexity; clang++ is just following the standard. However, the standard is likely going to change to more generally allow you to write const Foo f; as long as the constructor will, in fact, initialize every subobject.

Finally, will Foo f{}; always zero-initialize members of built-in type if Foo::Foo(void) is {}, =default, or implicitly-declared?

Yes for the latter two. No for the first. That one counts as user-provided, so value-initialization doesn't perform zero-initialization before calling the default constructor.

like image 113
T.C. Avatar answered Oct 26 '22 18:10

T.C.