1

I'm trying to initialize an array of objects with 0 like this (simplified code of a more complex project) :

#include <iostream>

struct Vector {
    float s[4];
    Vector() {}
    static Vector zero() {
        Vector v;
        v.s[0] = 0;
        v.s[1] = 0;
        v.s[2] = 0;
        v.s[3] = 0;
        return v;
    }
};

struct Test {
    Vector v[4] = { Vector::zero() };
};


int main(int argc, char** argv)
{
    Test t;
    for (int i = 0; i < 4; i++) {
        printf("%f %f %f %f\n", t.v[i].s[0], t.v[i].s[1], t.v[i].s[2], t.v[i].s[3]);
    }
    return 0;
}

This code should print all 0, but sometimes it prints different values. Looks like only the first element of the array is initialized. But if I write float x[4] = { 0 }, then all elements of the array x are initialized with 0. What is the difference and where in the C++ standard can I read about this behavior?

Frank Buss
  • 714
  • 7
  • 14

1 Answers1

6

I think you might want to look here: https://en.cppreference.com/w/cpp/language/aggregate_initialization

With

Vector v[4] = { Vector::zero() };

You initialize the first element, the other 3 are initialized with calls to the default ctor that does not initialize the array (the body of your default ctor is empty).

Substitute at the beginning the array declaration with

float s[4]{};

This will value-initialize the array, zeroing it. Then you can remove everything else.

To read the relationship between value-initialization and zero-initialization, please refer to https://en.cppreference.com/w/cpp/language/value_initialization

Furthermore, as noted by user Kenny Ostrom in the comments, you might want to consider using std::array, keeping in mind that you will need still to value-initialize it, see Default initialization of std::array? . Lastly, as noted in the comments access to x[4] is Undefined Behavior.

  • Thanks, I fixed the x[4] access in my original posting. I don't know if I can change it to std::array, it is within an union and has some alignment requirements. The original code where the problem happened is here: https://github.com/VCVRack/Fundamental/blob/01fe49d256df8d10c901e1cbad693bb5ec50f04a/src/ADSR.cpp#L41 And this is the problematic line without initialization, which I now suggested to change to your solution: https://github.com/VCVRack/Rack/blob/d89034b01c0dc13ecc2a374d82610334d557f8cc/include/simd/vector.hpp#L40 (the same file has a typedef for float_4) – Frank Buss Jun 23 '19 at 18:01
  • IMHO the substitution should be fine, but I am not sure, I am not a fan of unions, see https://stackoverflow.com/questions/21763002/is-it-safe-to-put-an-stdarraypod-n-in-a-union. You might want to consider using a variant (std or boost) instead of a plain union. – CuriouslyRecurringThoughts Jun 23 '19 at 18:06
  • @FrankBuss again, not an expert on unions here, but I am afraid that my solution might not be suitable for your particular use-case, please see https://stackoverflow.com/questions/11812555/how-to-zero-initialize-an-union – CuriouslyRecurringThoughts Jun 23 '19 at 19:42
  • The developer has zeroed it now in the constructor: https://github.com/VCVRack/Rack/commit/01d60a0bb14e25486ff8e644a096b53dcf154183 Should be safe. The only problem is that it assumes sizeof(float)==4, but might work on all supported platforms. – Frank Buss Jun 23 '19 at 19:58
  • Great! You can consider adding a static_asset(sizeof(float) == 4, "ERROR") to the code so that if the size is not 4 it won't compile and you know it compile-time instead of runtime. Regards – CuriouslyRecurringThoughts Jun 23 '19 at 20:00
  • He changed it again so that it behaves now like a simple type. Now the Vector class has this constructor: Vector() = default; So this works now as expected: Vector v[4] = { 0 }; I still don't like it, I think it is a design flaw of C++ that it is possible to use uninitialized values. I understand that it needs some more instructions and time, but shouldn't matter much these days. – Frank Buss Jun 24 '19 at 09:40