c++initializationinitializer-listobject-initializers

Why does my array initializer not work unless I create a separate variable for it?


The following C++ code compiles with no errors or warnings, but for some reason when I print out the contents of foo.arr I just get junk values. It looks like the array member is not being properly initialized.

template<int n> class C{
  public:
  const uint8_t (&arr)[n];
  const int length = n;
  C(const uint8_t (&arr_arg)[n]):arr(arr_arg)
  {}
};

int main() {
    C<5> foo{{1,2,3,4,5}};
    for(int i =0;i<foo.length;i++){      
      printf("foo.arr[%d]=%2x\r\n",i,foo.arr[i]);
    };
}

But if I write it like this, foo.arr is correctly initialized when I print out the results.

int main() {
    const uint8_t x[]{1,2,3,4,5};
    C<5> foo{x};
    for(int i =0;i<foo.length;i++){      
      printf("foo.arr[%d]=%2x\r\n",i,foo.arr[i]);
    };
}

Why does the second case work, but the first one doesn't?

One would think that the compiler would create a block of five bytes for the constant data {1,2,3,4,5} and then the initializer for foo would point foo.arr to that block of bytes. It seems that whatever foo.arr is pointing either not where that data is, or else that data doesn't exist any more by the time I print it out (possibly overwritten).


Solution

  • C<5> foo{{1,2,3,4,5}};
    

    The constructor's parameter is a reference to a temporary object that gets destroyed after the constructor call finishes. All subsequent reference to this object results in undefined behavior.

    C<5> foo{x};
    

    Here, the constructor's parameter is a reference to an object that remains in scope and continues to exist as long as it is subsequently referenced and used.

    It seems that ... data doesn't exist any more by the time I print it out (possibly overwritten).

    That is, indeed, what's happening.