Does C++ zero-initialise unspecified values during aggregate initialization?

房东的猫 提交于 2020-04-18 06:12:33

问题


An interesting question arose as a side effect of some other question here, about the possible differences between how C and C++ handle (the non-static-storage-duration):

int arr[7] = {0};

Someone was stating that, in C++, the other elements were not guaranteed to be zero but I'm not sure I agree.

Now C11 states, in 6.7.9 Initialization /19:

The initialization shall occur in initializer list order, each initializer provided for a particular subobject overriding any previously listed initializer for the same subobject; all subobjects that are not initialized explicitly shall be initialized implicitly the same as objects that have static storage duration.

This means that the other six elements of arr will be initilised to zero (since static int x; would initialise x to zero).


I'm unsure if this is also the case for C++. In the C++20 standard, 9.3.1 Aggregates /3 states:

When an aggregate is initialized by an initializer list as specified in 9.3.4, the elements of the initializer list are taken as initializers for the elements of the aggregate. The explicitly initialized elements of the aggregate are determined as follows:

(3.1) — (irrelevant stuff to do with designated initialiser lists and classes - pax).

(3.2) — If the initializer list is an initializer-list, the explicitly initialized elements of the aggregate are the first n elements of the aggregate, where n is the number of elements in the initializer list.

Then /4 states how the explicit initialisations work, and /5 handles the non-explicit cases:

For a non-union aggregate, each element that is not an explicitly initialized element is initialized as follows:

(5.1) — If the element has a default member initializer (10.3), the element is initialized from that initializer.

(5.2) — Otherwise, if the element is not a reference, the element is copy-initialized from an empty initializer list (9.3.4).

(5.3) — Otherwise, the program is ill-formed.

It appears to me that our particular case is covered by (5.2) so we have to go to 9.3.4 to see what happens to an int initialised with an empty list ({}). This goes through a lot of cases but I believe the first one that matches is:

(3.11) — Otherwise, if the initializer list has no elements, the object is value-initialized.

And, from 9.3 Initializers /8:

To value-initialize an object of type T means:

(8.1) — if T is a (possibly cv-qualified) class type (Clause 10) with either no default constructor (10.3.4) or a default constructor that is user-provided or deleted, then the object is default-initialized;

(8.2) — if T is a (possibly cv-qualified) class type without a user-provided or deleted default constructor, then the object is zero-initialized and the semantic constraints for default-initialization are checked, and if T has a non-trivial default constructor, the object is default-initialized;

(8.3) — if T is an array type, then each element is value-initialized;

(8.4) — otherwise, the object is zero-initialized.

Hence, it's 8.4 which seems to be the controlling clause, meaning C++ will also initialise the non-explicit elements of the array to zero.

Is my reasoning correct? Will C++, on encountering int arr[7] = {0};, set all elements to zero?


回答1:


Yes. C++ generally maintains backward compatibility with C, allowing you to include and use C code. Consider if you have some legacy C code, that attempts to initialize an array like you describe:

int arr[7] = {0};

If C++ worked any differently, and the C program (validly, under C) assumed that this array is zero initialized, then the code is liable to fail if included in a C++ project compiled with a C++ compiler.

Just to confirm, I compiled this C++ program using Cygwin g++ on x64 Windows:

int main() {
    int arr[7] = {0};
}

and then disassembled function main in GDB:

push   %rbp
mov    %rsp,%rbp
sub    $0x40,%rsp
callq  0x1004010d0 <__main>
movq   $0x0,-0x20(%rbp)
movq   $0x0,-0x18(%rbp)
movq   $0x0,-0x10(%rbp)
movl   $0x0,-0x8(%rbp)
mov    $0x0,%eax
add    $0x40,%rsp
pop    %rbp
retq

As you can see, the program moves 3 qwords and 1 dword worth of zeros into the stack. That's 28 bytes, which is the size of 7 ints on my system.



来源:https://stackoverflow.com/questions/61053225/does-c-zero-initialise-unspecified-values-during-aggregate-initialization

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!