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 */
};
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 forT
is called (and the initialization is ill-formed ifT
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 ofT
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 of0
(zero) converted toT
;- 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:
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 fromname
by calling thec_str
member function:const char* CStringName = name.c_str();
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 withstrcpy
: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 tochar studentName[40]
, since you can't pass arrays as parameters by value, which is why the compiler just treats it as achar*
pointing to the firstchar
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
Precise Thread Sleep Needed. Max 1Ms Error
Should I Worry About the Alignment During Pointer Casting
Boost::Asio:Io_Service.Run() VS Poll() or How to Integrate Boost::Asio in Mainloop
How to Redirect Stdout to Some Visible Display in a Windows Application
Error Enabling Openmp - "Ld: Library Not Found for -Lgomp" and Clang Errors
What's the Meaning of * and & When Applied to Variable Names
Why Is 'I = ++I + 1' Unspecified Behavior
How to Parse Date/Time from String
C++ Boost: Undefined Reference to Boost::System::Generic_Category()
Overriding Public Virtual Functions with Private Functions in C++
How to Use Visual Studio 2010's C++ Compiler with Visual Studio 2008's C++ Runtime Library
Where Is '%P' Useful with Printf
Std::Vector to Boost::Python::List
Performance of Unsigned VS Signed Integers