How to Use Member Initialization List to Initialize an Array

Initializing a member array in constructor initializer

  1. How can I do what I want to do (that is, initialize an array in a constructor (not assigning elements in the body)). Is it even possible?

Yes. It's using a struct that contains an array. You say you already know about that, but then I don't understand the question. That way, you do initialize an array in the constructor, without assignments in the body. This is what boost::array does.

Does the C++03 standard say anything special about initializing aggregates (including arrays) in ctor initializers? Or the invalidness of the above code is a corollary of some other rules?

A mem-initializer uses direct initialization. And the rules of clause 8 forbid this kind of thing. I'm not exactly sure about the following case, but some compilers do allow it.

struct A {
char foo[6];
A():foo("hello") { } /* valid? */
};

See this GCC PR for further details.

Do C++0x initializer lists solve the problem?

Yes, they do. However your syntax is invalid, I think. You have to use braces directly to fire off list initialization

struct A {
int foo[3];
A():foo{1, 2, 3} { }
A():foo({1, 2, 3}) { } /* invalid */
};

How can i use member initialization list to initialize an array?

The only sensible thing you can do with a C-array in C++03 is value-initialize it (in C++11 and beyond it can be list-initialized).

From the C++03 standard, §8.5/7:

An object whose initializer is an empty set of parentheses, i.e., (), shall be value-initialized.

And from §8.5/5:

To value-initialize an object of type T means:

  • if T is a class type with a user-declared constructor, then the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);
  • if T is a non-union class type without a user-declared constructor, then every non-static data member and base-class component of T is value-initialized;
  • if T is an array type, then each element is value-initialized;
  • otherwise, the object is zero-initialized

To zero-initialize an object of type T means:

  • if T is a scalar type, the object is set to the value of 0 (zero) converted to T;
  • if T is a non-union class type, each nonstatic data member and each base-class subobject is zero-initialized;
  • if T is a union type, the object’s first named data member) is zero-initialized;
  • if T is an array type, each element is zero-initialized;
  • if T is a reference type, no initialization is performed.

So, if your constructor definition is changed to

A::A() : a(), ptr() { }

then you are guaranteed that post-construction, all 5 elements of A::a will have the value '\0' and A::ptr will be null.

Initialize a constant sized array in an initializer list

While not available in C++03, C++11 introduces extended initializer lists. You can indeed do it if using a compiler compliant with the C++11 standard.

struct Test {
Test() : set { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 } { };
int set[10];
};

The above code compiles fine using g++ -std=c++0x -c test.cc.


As pointed out below me by a helpful user in the comments, this code does not compile using Microsoft's VC++ compiler, cl. Perhaps someone can tell me if the equivalent using std::array will?

#include <array>

struct Test {
Test() : set { { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 } } { };
std::array<int, 10> set;
};

This also compiles fine using g++ -std=c++0x -c test.cc.

How to initialize an array in the member initializer list

Since you can't initialize (raw) arrays with other arrays or even assign arrays in C++, you basically have two possibilities:

  1. The idiomatic C++ way would be to use std::string, and the task becomes trivial:

    class Student{
    public:
    Student(int studentID, const std::string& studentName)
    : id(studentID), name(studentName) {}
    protected:
    std::string name;
    int id;
    };

    Then, when needed, you can get the underlying raw char array from name by calling the c_str member function:

    const char* CStringName = name.c_str();
  2. If you want to use a char array instead, things get more complicated. You can first default-initialize the array and fill it in the constructor body with strcpy:

    class Student{
    public:
    Student(int studentID, const char* studentName)
    : id(studentID) {
    assert(strlen(studentName) < 40); // make sure the given string fits in the array
    strcpy(name, studentName);
    }
    protected:
    char name[40];
    int id;
    };

    Note that the argument char* studentName is identical to char studentName[40], since you can't pass arrays as parameters by value, which is why the compiler just treats it as a char* pointing to the first char in the array.

How to initialize std::array member in constructor initialization list when the size of the array is a template parameter

std::index_sequence was provided in order to simplify the metaprogramming task of creating and expanding a pack whose size is not fixed. Use std::make_index_sequence and delegate the construction to some private constructor that deduces the pack:

A(H h) : A(h, std::make_index_sequence<N>{}) {}

template <std::size_t... i>
A(H h, std::index_sequence<i...>) : hashes{((void)i, h)...} {}

Here, ((void)i, h) is a comma expression that evaluates to h, but since we mentioned the pack i inside it, it's eligible to be expanded using .... The result is N copies of h (one for each element of i). This expansion occurs inside a braced-init-list, so the result is a braced-init-list contaning N copies of h, which will then initialize the hashes member.

Zero-Initialize array member in initialization list

Initialising any member with () performs value initialisation.

Initialising any class type with a default constructor with {} performs value initialisation.

Initialising any other aggregate type (including arrays) with {} performs list initialisation, and is equivalent to initialising each of the aggregate's members with {}.

Initialising any reference type with {} constructs a temporary object, which is initialised from {}, and binds the reference to that temporary.

Initialising any other type with {} performs value initialisation.

Therefore, for pretty much all types, initialisation from {} will give the same result as value initialisation. You cannot have arrays of references, so those cannot be an exception. You might be able to construct arrays of aggregate class types without a default constructor, but compilers are not in agreement on the exact rules. But to get back to your question, all these corner cases do not really matter for you: for your specific array element type, they have the exact same effect.

Initializing member array in constructor initialization list (before C++11)

You may want to take a look as this related question on StackOverflow : using static functions to initialize your member arrays in initialization list can achieve what you are looking for :

class MyClass
{
typedef std::array< int, 2 > t_myA;
static t_myA fillFunction(){ static t_myA const ret = {1,2}; return ret; };

t_myA myArray;

public MyClass();
}

MyClass::MyClass()
: myArray( fillFunction() )
{
}

How to Initialize an array using initializer-list C++

You can do as the error suggests. You can use a brace initializer for your arrays like

npc_next_best_spot() : x{}, y{}, value(-1), k(0), i{}, triple_ress{}, triple_number{}, bigI(0) {}

Leaving the list blanks works as any missing initializer will zero initialize the element in the array.

Passing an initialization list to an array member in C++

The problem you are having is that you are trying to initialize pointer members with std::initializer_list, which is simply not possible.

You can, however, use std::array (since c++ 11). Here is a simplified example:

#include <iostream>
#include <array>

#define MAX_GFX_PLANES (4U)

struct chr_def {
// Constructor
chr_def(size_t size, const std::array<unsigned int, MAX_GFX_PLANES>& planeoffset) :
size(size), planeoffset(planeoffset) { };

// Data Members
const size_t size;
const std::array<unsigned int, MAX_GFX_PLANES> planeoffset;
};

const static chr_def nintendo_sfc{ 8U, {0U, 1U, 2U, 3U} };

int main() {
// std::array can be used with range-based for
for (auto i : nintendo_sfc.planeoffset) {
std::cout << i << " ";
}
return 0;
}


Related Topics



Leave a reply



Submit