How can I declare a two-dimensional array of pointers and initialize it by null pointers in c++ ?
I tried to do this
int *arr[20][30]= nullptr;
You can aggregate initialize the array with empty initializer list,
int *arr[20][30] {};
// or
int *arr[20][30] = {};
(emphasis mine)
If the number of initializer clauses is less than the number of members and bases (since C++17) or initializer list is completely empty, the remaining members and bases (since C++17) are initialized by their default member initializers, if provided in the class definition, and otherwise (since C++14) by empty lists, in accordance with the usual list-initialization rules (which performs value-initialization for non-class types and non-aggregate classes with default constructors, and aggregate initialization for aggregates).
Then all the elements of arr (i.e. the sub-array int* [30]) would be aggregate-initialized with empty initializer list too, then all the elements of sub-array with type int* would be value-initialized,
otherwise, the object is zero-initialized.
At last elements with type int* (which is built-in type) are all zero-initialized to null pointers.
If T is a scalar type, the object's initial value is the integral constant zero explicitly converted to T.
Related
Consider some type T (for simplicity, you may assume int) and some integral constant N, which we use to define an array like this:
T array[N]{}; // Note the empty braces here!
According to cppreference, value initialization is defined as follows:
This is the initialization performed when an object is constructed with an empty initializer.
But further down it is written:
In all cases, if the empty pair of braces {} is used and T is an aggregate type, aggregate-initialization is performed instead of value-initialization.
But then a little bit more down, the following statement appears:
if T is an array type, each element of the array is value-initialized;
From my understanding, the first and third quoted statements contradict to the second one.
So my two questions are:
Is the code snippet above a value initialization or an aggregate initialization?
Do the three quoted statements really contradict or am I missing something?
Note: I've seen similar questions here but they all differ a bit in the specifics.
Is T array[N]{} a value initialization or aggregate initialization?
It is list initialization and part of this initialization process involves aggregate initialization as per dcl.init.list. Additionally, it is also direct list initialization as quoted below.
1) List-initialization is initialization of an object or reference from a braced-init-list. Such an initializer is called an initializer list, and the comma-separated initializer-clauses of the initializer-list or designated-initializer-clauses of the designated-initializer-list are called the elements of the initializer list. An initializer list may be empty. List-initialization can occur in direct-initialization or copy-initialization contexts; list-initialization in a direct-initialization context is called direct-list-initialization and list-initialization in a copy-initialization context is called copy-list-initialization.
[Note 1 : List-initialization can be used
(1.1) as the initializer in a variable definition ([dcl.init])
...
— end note]
The above means that T array[N]{} is list-initialization.
Now let's move on to how the elements of the array is initialized which is given in dcl.init.list#3:
3) List-initialization of an object or reference of type T is defined as follows:
3.4) Otherwise, if T is an aggregate, aggregate initialization is performed.
And since in our example T array[N] is an aggregate, the above implies that in our example the whole process of initialization of the array T array[N] involves aggregate initialization.
Finally, from aggregate initialization given below, we will note that each element is copy-initialized from an empty initializer list:
3) When an aggregate is initialized by an initializer list as specified in [dcl.init.list], the elements of the initializer list are taken as initializers for the elements of the aggregate. The explicitly initialized elements of the aggregate are determined as follows:
3.3) Otherwise, the initializer list must be {}, and there are no explicitly initialized elements.
The above means that there are no explicitly initialized elements in our example so we move onto dcl.init.aggr#5:
5) For a non-union aggregate, each element that is not an explicitly initialized element is initialized as follows:
5.2) Otherwise, if the element is not a reference, the element is copy-initialized from an empty initializer list.
(emphasis mine)
Essentially, this means that each element of type T of the array will be initialized from an empty initializer list.
Note that this also explains why the following contrived example fails in C++20:
struct T
{
T() = delete;
};
int main()
{
T array[5]{}; //this fails as a consequence of above explanation
}
With C++11 std::array, do I have the guarantee that the syntax std::array<T, N> x; will default-initialize all the elements of the array ?
EDIT: if not, is there a syntax that will work on all arrays (including zero-sized arrays) to initialize all elements to their default value?
EDIT: on cppreference, the default constructor description says:
(constructor) (implicitly declared) (public member function)
default-constructs or copy-constructs every element of the array
so the answer may be yes. But I would like to be sure of that according to the standard or future standard.
By definition, default initialization is the initialization that occurs when no other initialization is specified; the C++ language guarantees you that any object for which you do not provide an explicit initializer will be default initialized (C++11 §8.5/11). That includes objects of type std::array<T, N> and T[N].
Be aware that there are types for which default initialization has no effect and leaves the object's value indeterminate: any non-class, non-array type (§8.5/6). Consequently, a default-initialized array of objects with such types will have indeterminate value, e.g.:
int plain_int;
int c_style_array[13];
std::array<int, 13> cxx_style_array;
Both the c-style array and std::array are filled with integers of indeterminate value, just as plain_int has indeterminate value.
Is there a syntax that will work on all arrays (including zero-sized arrays) to initialize all elements to their default value?
I'm guessing that when you say "to their default value" you really mean "initialize all elements to T{}". That's not default-initialization, it is value-initialization (8.5/7). You can request value initialization quite easily in C++11 by giving each declaration an empty initializer:
int plain_int{};
int c_style_array[13]{};
std::array<int, 13> cxx_style_array{};
Which will value-initialize all of the array elements in turn, resulting in plain_int, and all the members of both kinds of arrays, being initialized to zero.
Default-initialization is a term from the Standard potentially meaning no initialization at all, so you probably mean zero-initialization.
The description at cppreference.com is actually a bit misleading. std::array is an aggregate class, and if the element type is primitive, it is POD: "plain old data," with semantics closely matching the C language. The implicitly-defined constructor of std::array< int, N > is a trivial one which does absolutely nothing.
Syntax like std::array< int, 3 >() or std::array< int, 3 > x{} which provide zeroed values do not do so by invoking a constructor. Getting zeroes is part of value-initialization, specified in C++11 §8.5/8:
To value-initialize an object of type T means:
— if T is a (possibly cv-qualified) class type without a user-provided or deleted default constructor, then the object is zero-initialized …, and if T has a non-trivial default constructor, the object is default-initialized;
std::array has no user-provided default constructor, so it gets zero-initialized. It has an implicitly-defined default constructor, but it is trivial, so it is never default-initialized. (But this doesn't make a difference since trivial initialization by definition has no effect at runtime.)
if not, is there a syntax that will work on all arrays (including zero-sized arrays) to initialize all elements to their default value?
C-style arrays and std::array are both aggregates, and the way to completely zero-initialize any aggregate is with the syntax = {}. This works since C++98. Note that C-style arrays cannot have zero extent, and that sizeof (std::array< X, 0 >) is not zero.
Both T x[N]; and std::array<T, N> x; default-initialize every element of the array.
For example, if T = std::string, every element will be an empty string. If T is a class without a default constructor, both will fail to compile. If T = int, every element will have indeterminate value (unless that declaration happens to be at namespace scope)
C++11 std::array::fill is a good option for some cases.
First of all, T x[N] does default initialize the elements, although default initialization of a scalar type T actually does nothing. The above also holds for std::array x. I think what you need is list initialization.
Just switched to C++11 from C++03, and I was wondering, is the following defined to always zero initialize the array data for all elements?
template<size_t COUNT>
class Test {
public:
uint32 data[COUNT] = {};
};
Yes it's guaranteed; list initialization turns to aggregate initialization for array type:
Otherwise, if T is an aggregate type, aggregate initialization is performed.
then for aggregate initialization:
If the number of initializer clauses is less than the number of members or initializer list is completely empty, the remaining members are initialized by empty lists, in accordance with the usual list-initialization rules (which performs value-initialization for non-class types and non-aggregate classes with default constructors, and aggregate initialization for aggregates).
So all the elements of data will be value initialized, for uint32 they'll be zero-initialized at last.
otherwise, the object is zero-initialized.
I have a class with an array member that I would like to initialize to all zeros.
class X
{
private:
int m_array[10];
};
For a local variable, there is a straightforward way to zero-initialize (see here):
int myArray[10] = {};
Also, the class member m_array clearly needs to be initialized, as default-initializing ints will just leave random garbage, as explained here.
However, I can see two ways of doing this for a member array:
With parentheses:
public:
X()
: m_array()
{}
With braces:
public:
X()
: m_array{}
{}
Are both correct? Is there any difference between the two in C++11?
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.
The types of initialization can be kind of tedious to go through, but in this case it is trivial. For:
public:
X()
: m_array()
{}
since the expression-list between the parentheses are empty, value-initialization occurs. Similarly for:
public:
X()
: m_array{}
{}
list-initialization occurs, and subsequently value-initialization since the brace-init-list is empty.
To give a more comprehensive answer, let's go through §8.5 of N4140.
If no initializer is specified for an object, the object is
default-initialized. When storage for an object with automatic or
dynamic storage duration is obtained, the object has an indeterminate
value, and if no initialization is performed for the object, that
object retains an indeterminate value until that value is replaced
(5.17).
This indeterminate value is what you refer to as garbage values.
To zero-initialize an object or reference of type T means:
— if T is an array type, each element is zero-initialized
To value-initialize an object of type T means:
— if T is a (possibly cv-qualified) class type ... then the object is default-initialized; ...
— if T is an array type, then each element is value-initialized;
— otherwise, the object is zero-initialized.
The semantics of initializers are as follows. ...
— If the initializer is a (non-parenthesized) braced-init-list, the object or reference is list-initialized (8.5.4).
— If the initializer is (), the object is value-initialized.
So far it's clear that value initialization will make each element of the array zero since int is not a class type. But we have not yet covered list initialization and aggregate initialization, since an array is an aggregate.
§8.5.4:
List-initialization of an object or reference of type T is defined as follows:
— If T is an aggregate, aggregate initialization is performed (8.5.1).
And back to §8.5.1:
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 its brace-or-equal-initializer
or, if there is no brace-or-equal-initializer, from an empty
initializer list (8.5.4).
And we end with §8.5.4 again:
List-initialization of an object or reference of type T is defined as follows:
— Otherwise, if the initializer list has no elements, the object is value-initialized.
Since traversing the (draft) standard can take breath out of you, I recommend cppreference as it breaks it down pretty good.
Relevant links:
cppreference:
aggregate initialization
value initialization
Draft standard:
N4140
Parentheses work in C++98, and are calling for zero initialization, which is what you want. I verified on gcc 4.3. Edit: removed incorrect statement about C++11. I also confirmed that empty braces perform empty-list-initialization using clang 3.4 with -std=c++11.
I get mixed responses for this question on 2-d array initialization in C++.
Here's the scenario:
class MyClass {
private:
static char my2dArray[10][20];
};
char MyClass::my2dArray[10][20] = {{0}};
Now does this initialize all elements of this array with 0?
Also, if I have the following type definition:
typedef unsigned char u8;
and this array is static u8 my2dArray[10][20], will the same initialization work?
Assuming it's mandatory that all elements are explicitly initialized to 0.
Now does this initialize all elements of this array with 0?
Yes
If the initializer list does not have the same number of elements as the actual array. Then the array is zero filled.
will the same initialization work?
Yes
The same processes is at work here.
class MyClass {
private:
static char my2dArray[10][20];
};
char MyClass::my2dArray[10][20] = {{0}};
Now does this initialize all elements of this array with 0?
Sort of.
Recall that the elements of your array are not char, but char[10] (which cannot be 0).
What you're doing here is initialising the outer array by providing an initialiser for the first inner array ({0}, again setting only the inner array's first element to 0).
You're then letting the "default", implicit initialization behaviour take over for the subsequent elements in both arrays.
[n3290: 8.5.1/1]: An aggregate is an array or a class (Clause 9)
with no user-provided constructors (12.1), no
brace-or-equal-initializers for non-static data members (9.2), no
private or protected non-static data members (Clause 11), no base
classes (Clause 10), and no virtual functions.
[n3290: 8.5.1/2]: When an aggregate is initialized by an initializer
list, as specified in 8.5.4, the elements of the initializer list are
taken as initializers for the members of the aggregate, in increasing
subscript or member order. Each member is copy-initialized from the
corresponding initializer-clause. If the initializer-clause is an
expression and a narrowing conversion (8.5.4) is required to convert
the expression, the program is ill-formed. [ Note: If an
initializer-clause is itself an initializer list, the member is
list-initialized, which will result in a recursive application of the
rules in this section if the member is an aggregate. —end note ]
[n3290: 8.5.1/7:] 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).
[n3290: 8.5.4/3:] [..] Otherwise, if the initializer list has no
elements, the object is value-initialized. [..]
The [final draft] standard actually contains a non-normative example of a similar behaviour:
[n3290: 8.5.1/10]: [..] [ Example: [..] On the other hand,
float y[4][3] = { { 1 }, { 2 }, { 3 }, { 4 } };
initializes the first column of y (regarded as a two-dimensional
array) and leaves the rest zero. —end example ]
So, ultimately, yes. All of your innermost array elements will hold the value 0; it's just that your {{0}} didn't actually do very much to make that happen.
Assuming it's mandatory that all elements are explicitly initialized to 0.
Well, since your array has static storage duration, its memory will be zero-initialised anyway, so this is ultimately pointless to bother concerning yourself over.
Also, if I have the following type definition:
typedef unsigned char u8;
and this array is static u8 my2dArray[10][20], will the same initialization work?
Yes. The type alias doesn't change anything: this array has precisely the same type (and storage duration) as the first one, and the same rules apply.