Initializing a Member Array in Constructor Initializer

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 */
};

Initialize an array inside Constructor in C++

You can initialize the array in the constructor member initializer list

A::A() : array{2,3,4,1,6,5,4} {

}

or for older syntax

A::A() : array({2,3,4,1,6,5,4}) {

}

Your sample should compile, using a compiler supporting the latest standard though.


Also note your class declaration is missing a trailing semicolon

class A{
public:
int array[7];
A();
};
// ^

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.

C++: Initialize a member array within a constexpr constructor

The explanation is going to be long, but bear with me.


You can't initialize an array with an std::initializer_list.

When you write something like int arr[] = {1,2,3}, the part enclosed in braces is not an std::initializer_list.

If you don't believe me, consider a similar initialization for a structure:

struct A {int x; const char *y;};
A a = {1, "2"};

Here, {1, "2"} can't possibly be an std::initializer_list, because the elements have different types.

The C++ grammar calls those brace-enclosed lists braced-init-lists.

std::initializer_list is a magical class (not implementable in standard C++, that is) that can be constructed from a braced-init-list.

As you noticed, std::initializer_list can't be used in place of a braced-init-list. "Braced-init-list" refers to a specific grammatical construct, so an initializer for an array (e.g. in a member init list) must literally be a brace-enclosed list. You can't save this list to a variable, and initialize an array with it later.

constexpr A() : data{'1','2','3'} {} // Valid
constexpr A(initializer_list<char>/*or whatever*/ list) : data{list} {} // Not possible

A possible solution is to use a loop to copy elements from std::initializer_list into the array.

Since the constructor is constexpr, the array must be initialized with something; initialize it with zeroes using : data{}:

constexpr A(std::initializer_list<char> s) : data{} {/*copy elements here*/}

Now A a({'1','2','3'}); will work. But A a("123"); still won't.

A string literal ("123") is neither a braced-init-list nor an std::initializer_list, and it can't be converted to them.

There's a special rule for initializing char arrays with string literals (char x[] = "123";). In addition to a braced-init-list, the grammar allows a string literal to be used there.

It has to be a string literal, i.e. a string enclosed in quotes; a const char * variable or an another array of char won't do.

If you want A a("123"); to be valid, the parameter of the constructor needs to be a const char * (there are some other options, but they don't help much here). Use a loop to copy the characters from the pointed memory into the array. Don't forget to initialize the array with zeroes (: data{}), because your constructor is constexpr.

There's a third option: replace char data[100] with an std::array, and also make the parameter of the constructor an std::array. Unlike plain arrays, those can be copied, so : data(list) will work. And std::array can be initialized with both a braced-init-list (A a({'1','2','3'});), and a brace-enclosed string literal (A a({"123"});).

And there's yet another option you have: remove the constructor. Your struct will then become an aggregate (simply saying, a struct that has no custom constructors and can be initialized member-wise with a braced-init-list). Then both A a{{'1','2','3'}};, A a{'1','2','3'}; (braces can be omitted), and A a{"123"}; will work.

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.

C++: constructor initializer for arrays

There is no way. You need a default constructor for array members and it will be called, afterwards, you can do any initialization you want in the constructor.

Zero-initializing an array data member in a constructor

Just use value initialization in the constructor initialization list. That is the idiomatic way of doing this in C++.

Cache::Cache() : byte()
{
}

Note that C++11 allows this syntax too:

Cache::Cache() : byte{}
{
}

In case you're wondering why this works, from the C++ 11 standard (note this also applies to C++03):

C++11 § 8.5,p10

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

That term value-initialized takes us to:

C++11 § 8.5,p7

To value-initialize an object of type T means:

  • if T is a (possibly cv-qualified) class type9 with a user-provided constructor (12.1), 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 (possibly cv-qualified) non-union class type without a user-provided constructor, then the object is zero-initialized and, if T’s implicitly-declared default constructor is non-trivial, that constructor is called.

  • if T is an array type, then each element is value-initialized;

  • otherwise, the object is zero-initialized.

The third option in this trips the value-initialization of each element; the fourth applies once we get to each of those elements because they're (a) no class types, so (1) and (2) are gone, and (b) not arrays, so (3) is gone. That leaves only the last one, and your elements are zero-initialized.

C++ Initialize Member Array with Constructor Argument

You can use std::index_sequence to get the indices of the array as a non-type template parameter pack. Then you can use a parameter pack expansion.

template<size_t Size>
struct Foo {
int const myVals[Size];
Foo(std::array<Input, Size> const &in)
: Foo(in, std::make_index_sequence<Size>()) { }
private:
template<size_t... Is>
Foo(std::array<Input, Size> const &in, std::index_sequence<Is...>)
: myVals{in[Is].value...} { }
}

Using a helper template with a size_t... Is pack and a std::index_sequence<Is...> argument is a common pattern for handling fixed-size indexable containers. The index_sequence doesn't actually do anything; it's just a proxy so that the Is template arguments can be deduced. E.g. if you check on Godbolt it appears to totally evaporate under -O1.

Initialize array of objects in constructor

Since MyClass(SomeCStruct* pCStruct) constructor doesn't (can't) initialize the TheOtherClass m_objects in the member initializer list, the m_objects will need to be default constructed at first, and then this member will be reassigned with new value in the body of the MyClass constructor.

The TheOtherClass won't have a synthesized constructor since you have defined (other, non-default) ctor that takes SomeCStruct* and int. Thus, no default constructor for it in your code.

Here, we define a default constructor:

class TheOtherClass {
SomeCStruct* m_pCStruct;
int m_ObjIdx;
public:
TheOtherClass() : m_pCStruct(nullptr), m_ObjIdx(0) {} // Default ctor
TheOtherClass(SomeCStruct* pCStruct, int ClassIdx)
: m_pCStruct(pCStruct),
m_ObjIdx(ClassIdx) {}
};

As to the MyClass. Since you've already pass the argument as a pointer MyClass(SomeCStruct* pCStruct), you don't need to take the address of it (as in &pCStruct).

And the main issue in the MyClass is that the m_objects is of class type TheOtherClass which does not define any operator=, including the one that takes brace-enclosed initializer list. So, you won't be able to do like so:

m_objects[4] = { // The operator '=' has not been defined for the TheOtherClass, also note the subscript
TheOtherClass(pCStruct, 1),
TheOtherClass(pCStruct, 2),
TheOtherClass(pCStruct,3),
TheOtherClass(pCStruct, 4)
};

Again, when you try to list initialize it, it has already been default constructed. Thus, for this approach to work you will need to define such copy-assignment operator to do this kind of assignment to an already default constructed instance of the TheOtherClass. As to how to implement this operator, it will mostly depend on the overall design and other factors which were not mentioned in this thread.

Update

If you will have the following body of the MyClass constructor, it will work:

MyClass(SomeCStruct* pCStruct) : m_pMyCStruct(pCStruct) {
// Assign to default initialized TheOtherClass object
m_objects[0] = TheOtherClass(pCStruct, 1);
}

I would advise you to check these:

Operator overloading

Constructors and member initializer lists



Related Topics



Leave a reply



Submit