Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is a float member guaranteed to be zero initialized with {} syntax?

In C++17, consider a case where S is a struct with a deleted default constructor and a float member, when S is initialized with empty braces, is the float member guaranteed by the standard to be zero-initialized?

struct A {
  int x{};
};

struct S
{
  S() = delete;
 
  A a;
  float b;
};

int main()
{
  auto s = S{}; // Is s.b guaranteed to be zero?
}

In my opinion, cppreference.com is not clear, saying both that:

If the number of initializer clauses is less than the number of members and basesor initializer list is completely empty, the remaining members and bases (since C++17) are initialized by their default member initializers, if provided in the class definition, and otherwise (since C++14) copy-initialized from empty lists, in accordance with the usual list-initialization rules (which performs value-initialization for non-class types and non-aggregate classes with default constructors, and aggregate initialization for aggregates). If a member of a reference type is one of these remaining members, the program is ill-formed.

(from here), which implies that b is guaranteed to be zero

In all cases, if the empty pair of braces {} is used and T is an aggregate type, aggregate-initialization is performed instead of value-initialization.

(from here)

which implies that b is not guaranteed to be zero.

There is also a discussion that seems to imply that while not guaranteed, all known compiler zero-initialize anyway:

The standard specifies that zero-initialization is not performed when the class has a user-provided or deleted default constructor, even if that default constructor is not selected by overload resolution. All known compilers performs additional zero-initialization if a non-deleted defaulted default constructor is selected.

Related to Why does aggregate initialization not work anymore since C++20 if a constructor is explicitly defaulted or deleted?

like image 361
fouronnes Avatar asked Oct 18 '21 08:10

fouronnes


People also ask

Are class members initialized to zero?

If T is scalar (arithmetic, pointer, enum), it is initialized from 0 ; if it's a class type, all base classes and data members are zero-initialized; if it's an array, each element is zero-initialized.

Does C++ initialize variables to zero?

Unlike some programming languages, C/C++ does not initialize most variables to a given value (such as zero) automatically. Thus when a variable is assigned a memory location by the compiler, the default value of that variable is whatever (garbage) value happens to already be in that memory location!

Does New initialize memory 0?

Yes. That's kind of my point. If you make a new variable and see that's it's zero, you can't straight away assume that something within your program has set it to zero. Since most memory comes ready-zeroed, it's probably still uninitialised.

Are arrays zero initialized in C++?

The array will be initialized to 0 if we provide the empty initializer list or just specify 0 in the initializer list.


2 Answers

This is a quirk of C++ that is fixed in C++20. In the meantime you can add explicit to the deleted default constructor to force the struct to become non-aggregate, and make your code a guaranteed compile error:

struct A {
  int x{};
};

struct S
{
  explicit S() = delete;
 
  const A a;
  const float b;
};

int main()
{
  auto s = S{}; // error: call to deleted constructor of 'S'
}
like image 148
fouronnes Avatar answered Nov 29 '22 08:11

fouronnes


Because S is an aggregate, S{} will perform aggregate initialization. The rule in the standard about how members are initialized when there are no initializers in the list is basically what you cited:

  • If the element has a default member initializer ([class.mem]), the element is initialized from that initializer.
  • Otherwise, if the element is not a reference, the element is copy-initialized from an empty initializer list ([dcl.init.list]).

So for b, that's the equivalent of float b = {};. Per the rules of list initialization, we have to get all the way down to 3.10:

Otherwise, if the initializer list has no elements, the object is value-initialized.

And value initialization will initialize a float to 0.

like image 21
Nicol Bolas Avatar answered Nov 29 '22 08:11

Nicol Bolas