Initializing a member array in constructor initializer
- 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 anstd::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
Optional Parameters With C++ Macros
How to Get Iostream to Perform Better
Winmain and Main() in C++ (Extended)
C++11 Allows In-Class Initialization of Non-Static and Non-Const Members. What Changed
Resolving Ambiguous Overload on Function Pointer and Std::Function For a Lambda Using + (Unary Plus)
Is There an Implicit Default Constructor in C++
Exporting Classes Containing 'Std::' Objects (Vector, Map etc.) from a Dll
How to Print an Unsigned Char as Hex in C++ Using Ostream
Why Doesn't C++ Support Functions Returning Arrays
How to Check If a C++ String Is an Int
Convert Cstring to Const Char*
Overload Resolution Between Object, Rvalue Reference, Const Reference
Does Const-Correctness Give the Compiler More Room For Optimization
How to Read a Cmake Variable in C++ Source Code
Vectors, Structs and Std::Find
Templates: Parent Class Member Variables Not Visible in Inherited Class