16

I have just asked two questions about array and value initialization here and here. But with this code, I'm lost:

#include <iostream>
#include <iomanip>
#include <array>

template <class T, class U = decltype(std::declval<T>().at(0))>
inline U f1(const unsigned int i)
{T x; return x.at(i);}

template <class T, class U = decltype(std::declval<T>().at(0))>
inline U f2(const unsigned int i)
{T x = T(); return x.at(i);}

int main()
{
    static const unsigned int n = 10;
    static const unsigned int w = 20;
    for (unsigned int i = 0; i < n; ++i) {
        std::cout<<std::setw(w)<<i;
        std::cout<<std::setw(w)<<f1<std::array<int, n>>(i);
        std::cout<<std::setw(w)<<f2<std::array<int, n>>(i);
        std::cout<<std::setw(w)<<std::endl;
    }
    return 0;
}

As expected, f1 return arbitrary values as its values are not zero-initialized. But f2 seems to return exclusively zero values:

                   0                   0                   0
                   1                  61                   0
                   2                   0                   0
                   3                   0                   0
                   4           297887440                   0
                   5               32767                   0
                   6             4196848                   0
                   7                   0                   0
                   8           297887664                   0
                   9               32767                   0

Personally I thought that f2 will create an array with arbitrary values and copy/move it to x. But it does not seem to be the case.

So, I have two questions:

  • Why?
  • Do C++11 std::array<T, N> and C-style T[N] have the same behaviour in such a situation?
Community
  • 1
  • 1
Vincent
  • 57,703
  • 61
  • 205
  • 388
  • 3
    `T()` is a value-initialized `T`. And invalid syntax if `T` is a C-style array type. `T x = {};` or `T x{};` are more generally applicable syntaxes. – Casey Aug 18 '13 at 06:19
  • @Casey value initialization applies to C-style arrays. `T()` is a syntax error if `T` is not a simple-type-specifier, i.e. a single identifier or keyword which names a type. In C++03, `= {}` applies only to arrays and simple `{}` is an error. – Potatoswatter Aug 18 '13 at 06:35
  • The supposed duplicate is about value-initialization but this question is about default-initialization. Please reopen and find a proper duplicate, or just answer it. – Potatoswatter Aug 18 '13 at 06:42
  • @Potatoswatter I didn't suggest that value initialization doesn't apply to C-style arrays. A simple-type-specifier can also be type-name (including a typedef name) or a simple-template-id. The question is about C++11. – Casey Aug 18 '13 at 06:49
  • Note that 5.2.3/2 defines the functional-cast notation: "The expression `T()`, where `T` is a *simple-type-specifier* or *typename-specifier* for a **non-array** complete object type or the (possibly cv-qualified) `void` type, creates a prvalue of the specified type,which is value-initialized (8.5; no initialization is done for the `void()` case)." It explicitly forbids array types. – Casey Aug 18 '13 at 06:58
  • @Casey Okay. Even if it didn't forbid that, you can't have a prvalue of array type, and arrays aren't CopyConstructible, so `T x = T()` wouldn't work. Anyhoo, this is fodder for an answer, and the original question (of why default-initialization of such a class as `std::array` leaves its members uninitialized) remains unaddressed. – Potatoswatter Aug 18 '13 at 08:40
  • @Potatoswatter The question was "why does syntax A zero this array when syntax B does not?" I felt that my statement about the syntax was enough to differentiate the two, given that there were very comprehensive discussions about default initialization vs. value initialization in the answers to Vincent's two questions from earlier ([1](http://stackoverflow.com/questions/18295614/does-int-return-0-or-an-arbitrary-value)) ([2](http://stackoverflow.com/questions/18295302/default-initialization-of-stdarray)). – Casey Aug 18 '13 at 09:29
  • `std::array` is more like the C-style `struct S {T arr[N];};` than raw `T[N]`. `S x = S();` will also leave `x.arr` initialized to all zeros, for reasons explained by the previous comments. – Igor Tandetnik Aug 18 '13 at 13:48
  • @Casey Ah, (2) covers the question but was not previously linked from here. (1) does not. Anyway you mention "non-class, non-array types" but not trivial constructibility, which IIRC is the real determining factor. `std::array` is a class, hence his confusion. – Potatoswatter Aug 18 '13 at 23:20

1 Answers1

19

Using {} or () as an initializer, with our without =, results in value initialization. For a type with an implicitly-declared constructor, value initialization implements zero initialization, which as its name suggests sets each primitive element to 0. This occurs before the constructor may be run, but in this case, the constructor does nothing.

Because the constructor does nothing (it is trivial), it is possible to see uninitialized data.

As for C-style arrays, the behavior is similar if you use = {} instead of = T(), as the latter is illegal. T() would ask for a temporary array object to be assigned to the named object, but arrays can't be assigned. = {} on the other hand assigns a braced-initializer-list to the array, and a braced-initializer-list is a special syntactic construct which is neither an expression nor an object.

Potatoswatter
  • 134,909
  • 25
  • 265
  • 421