1

Consider the following code

std::vector<std::array<double,10>> a(10);

If I understand the standard correctly a will not be zero initialized, because en.cppreference.com on std::vector constructors says

  1. Constructs the container with count default-inserted instances of T. No copies are made.

So because default initializing std::array<double, 10> does not fill it with zeros, a will also not contain zeros.

Is this true?

How can I enforce zero initialization?

Will a.data() point to 100 continuous double values?

Edit:

This is the output from godbolt on gcc 10.2 with -O2

main:
        mov     edi, 800
        sub     rsp, 8
        call    operator new(unsigned long)
        mov     rdi, rax
        lea     rdx, [rax+800]
.L2:
        mov     QWORD PTR [rax], 0x000000000
        add     rax, 80
        mov     QWORD PTR [rax-72], 0x000000000
        mov     QWORD PTR [rax-64], 0x000000000
        mov     QWORD PTR [rax-56], 0x000000000
        mov     QWORD PTR [rax-48], 0x000000000
        mov     QWORD PTR [rax-40], 0x000000000
        mov     QWORD PTR [rax-32], 0x000000000
        mov     QWORD PTR [rax-24], 0x000000000
        mov     QWORD PTR [rax-16], 0x000000000
        mov     QWORD PTR [rax-8], 0x000000000
        cmp     rdx, rax
        jne     .L2
        mov     esi, 800
        call    operator delete(void*, unsigned long)
        xor     eax, eax
        add     rsp, 8
        ret

So it does seems to be zero initialized. Then the question remains why.

2
  • std::vector<std::array<double,10>> a(10, {0}); should zero-initialize, I think. Treating a.data() as an array of 100 doubles would exhibit undefined behavior, I believe. Commented Mar 30, 2021 at 17:27
  • Maybe not the most convenient way of doing it, but couldn't you just give an initializer list as default value for the vector constructor? Such that the array are then all initialized with it: std::vector<std::array<double,10>> a(10, {0,0,0,0,0,0,0,0,0,0});? Commented Mar 30, 2021 at 17:29

3 Answers 3

8

It's correct that the overload will default insert elements.

But you have to keep on reading, as default insertion means that the values inserted will be value initialized, and value-initializing an aggregate (like std::array) will value-initialize all elements in the aggregate.

And value initialization of double values will be the same as zero-initialization.

So all elements in each array of the vector will be initialized to zero.

Sign up to request clarification or add additional context in comments.

6 Comments

Thanks, this makes sense. Is using a.data() as a pointer to 100 double undefined behavior?
@Unlikus a.data() returns a pointer to the first element of the vector, which is a std::array<double, 10>*, not a double*. So no a.data() can't be used like that.
Nice answer! But this cppreference page is a bit confusing: note that default initialization may result in indeterminate values for non-class T.
@Unlikus std::array<double, 10> is a wrapper for a double[10], with no other data members (since std::array is an aggregate), so sizeof(std::array<double, 10>) is guaranteed to be at least sizeof(double)*10. std::vector is a contiguous buffer of elements, where each element in this case is a std::array<double, 10>. So the only guarantee is that a(10) would effectively be an array of 10 contiguous std:arrays. But not guaranteed to be a contiguous buffer of 100 doubles, because std::array may add extra padding after its inner array.
@Unlikus I'm not sure you will. The Dude's answer seems comprehensive - I'm just confused about what cppreference means.
|
1

To be sure that your arrays are zero-initialized, you can add a 1-element initializer list as a second argument to the a constructor call:

std::vector<std::array<double, 10>> a(10, { 0.0, });

This will initialize each element (array) using that list, as it will be using constructor version #3 described here in cppreference.

The 'value' argument used to initialize each array will use aggregate initialization (see here), which will zero-initialize any 'missing' values in the list.

Comments

0

You can do this as it is shown in the demonstrative program below:

#include <iostream>
#include <array>
#include <vector>

int main() 
{
    std::vector<std::array<double,10>> v(10, { {} } );
    
    for ( const auto &a : v )
    {
        for ( const auto &item : a )
        {
            std::cout << item << ' ';
        }
        std::cout << '\n';
    }
    
    
    return 0;
}

The program output is

0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.