Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can I initialize a regular array from {}, but not a std::array

This works:

int arr[10] = {};

All elements of arr are value-initialized to zero.

Why doesn't this work:

std::array<int, 10> arr({}); 

I get the following warning from g++ (version 4.8.2):

warning: missing initializer for member ‘std::array<int, 10ul>::_M_elems’

like image 371
AlwaysLearning Avatar asked Jul 07 '15 14:07

AlwaysLearning


People also ask

Does std :: array initialize?

std::array contains a built-in array, which can be initialized via an initializer list, which is what the inner set is. The outer set is for aggregate initialization.

How do you initialize an array of STD in C++?

Like arrays, we initialize an std::array by simply assigning it values at the time of declaration. For example, we will initialize an integer type std::array named 'n' of length 5 as shown below; std::array<int, 5> n = {1, 2, 3, 4, 5}; There is another way of initializing an std::array which is shown below.

What are the two ways to initialize the array?

There are two ways to specify initializers for arrays: With C89-style initializers, array elements must be initialized in subscript order. Using designated initializers, which allow you to specify the values of the subscript elements to be initialized, array elements can be initialized in any order.

Which type is correct for initializing an array?

The initializer for an array is a comma-separated list of constant expressions enclosed in braces ( { } ). The initializer is preceded by an equal sign ( = ). You do not need to initialize all elements in an array.


3 Answers

There are two issues one which is a matter of style and the warning.

Although it may not be obvious, aggregate initialization is happening on a temporary which is then being used as an argument to the copy constructor. The more idiomatic to do this initialization would be as follows:

std::array<int, 10> arr = {}; 

Although this still leaves the warning.

The warning is covered by gcc bug report: - -Wmissing-field-initializers relaxation request and one of the comments says:

[...]Surely, the C++ syntax of saying MyType x = {}; should be supported, as seen here:

http://en.cppreference.com/w/cpp/language/aggregate_initialization

where for instance:

struct S {
  int a;
  float b;
  std::string str;
};

S s = {}; // identical to S s = {0, 0.0, std::string};

That shouldn't warn for the reasons stated in earlier comments.

and a follow-up comment says:

My statement about zero-initialization was inaccurate (thanks), but the general point still stands: in C you have to write ' = {0}' since empty-braces initializer is not supported by the language (you get a warning with -pedantic); in C++, you can write ' = {}' or 'T foo = T();', but you don't need to write ' = {0}' specifically.

The latest versions of gcc does not produce this warning for this case, see it live working with gcc 5.1.

We can see this topic also covered in the Clang Developers lists in the thead: -Wmissing-field-initializers.

For reference the draft C++11 standard section 8.5.1 [dcl.init.aggr] says:

If there are fewer initializer-clauses in the list than there are members in the aggregate, then each member not explicitly initialized shall be initialized from an empty initializer list (8.5.4). [ Example:

struct S { int a; const char* b; int c; };
S ss = { 1, "asdf" };

initializes ss.a with 1, ss.b with "asdf", and ss.c with the value of an expression of the form int(), that is, 0. —end example ]

So as this is valid C++, although as noted using {} is not valid C99. One could argue that it is only a warning, but this seems like idiomatic C++ using {} for aggregate initialization and is problematic if we are using -Werror to turn warnings into errors.

like image 110
Shafik Yaghmour Avatar answered Oct 12 '22 11:10

Shafik Yaghmour


Firstly, you can use the ({}) initializer with an std::array object, but semantically that stands for direct-initialization using copy-constructor from a temporary value-initialized std::array object, i.e. it is equivalent to

std::array<int, 10> arr(std::array<int, 10>{}); 

And it is actually supposed to compile.

Secondly, you don't really have to go the ({}) way when you can just do

std::array<int, 10> arr = {};

or

std::array<int, 10> arr{};

The first of the two is the most syntactically similar to your int arr[10] = {};, which makes me wonder why you didn't try it at first. Why did you decide to use ({}) instead of = {} when you built the std::array version of = {} syntax?

like image 30
AnT Avatar answered Oct 12 '22 13:10

AnT


Enough people have pointed this out as a "problem" when compiling with -Werror that I think it's worth mentioning that the problem goes away if you just double up:

std::array<int, 10> arr{{}};

Does not produce any warning for me on gcc 4.9.2.

To add a bit as to why this solves it: my understanding was that std::array is actually a class with a C array as its only member. So double up on the braces makes sense: the outer braces indicate you are initializing the class, and then the inner braces default initialize the one and only member of the class.

Since there is no possible ambiguity when there is only one variable in a class, just using one pair of {} should be reasonable, but gcc is overly pedantic here, and warns.

like image 30
Nir Friedman Avatar answered Oct 12 '22 13:10

Nir Friedman