Say I have a struct
(or class) with a dynamic array, its length, and a constructor:
struct array {
int l;
int* t;
array(int length);
};
array::array(int length) {
l=length;
t=new int[l];
}
I assume everything so far is legal: this is how I would write it (although it maybe not be the only way to do things), but I have seen the following code, that somewhat seems to work:
struct array {
int l;
int* t = new int[l];
array(int length);
}
array::array(int length) {
l=length;
}
It looks bad, so I wonder if this works out of sheer luck and undefined behaviors, or if there is some internal rule that makes this code work fine.
This is the initialization performed when an object is constructed with no initializer.
From Java Language Specification. Each class variable, instance variable, or array component is initialized with a default value when it is created (§15.9, §15.10): For type byte, the default value is zero, that is, the value of (byte)0. For type short, the default value is zero, that is, the value of (short)0.
This default initializer propagates into all constructors for that class, even constructors that C++ synthesizes. Initializing members in this way is useful for classes with lots of data members, especially for types such as bool , int , double , and raw pointers.
This code is not correct.
int* t = new int[l];
will happen before l=length;
, thus reading the uninitialized variable l
. Member initializers are handled before the constructor's body runs.
array::array(int length) : l{length} {}
instead would work because l
is declared before t
.
However, doing this "by hand" is a bad idea to begin with. You should be using std::vector
.
The 2nd code snippet might have undefined behavior.
The data members are initialized at the order of how they're declared. For class array
, when t
is initialized l
is not initialized yet. For objects with automatic and dynamic storage duration l
will be initialized to indeterminate value, then the usage of l
(i.e. new int[l]
) leads to UB.
Note that l=length;
inside the body of the constructor is just assignment; the initialization of data members has been finished before that.
BTW: With member initializer list the 1st code snippet chould be rewritten as
array::array(int length) : l(length), t(new int[l]) {
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With