Why new T[10] Differs on Windows vs Linux: Default vs Value Initialization in C++
The article explains why allocating an array with new sample[10] yields zero‑initialized memory on Linux but uninitialized memory on Windows, clarifies the difference between default and value initialization in C++, and shows how various new expressions behave with concrete code examples.
On a Windows development machine a colleague reported a crash when debugging a core trading component of the product. The crash was caused by dereferencing an uninitialized pointer in a struct array allocated with new sample[10]. The relevant snippet is:
struct sample {
int* ptr_table[4][4];
// ... other members
};
void test() {
sample* sample_ptr = new sample[10];
for (int i = 0; i < 4; i++)
sample_ptr[0].ptr_table[0][i] = new int(i);
int* int_ptr = sample_ptr[0].ptr_table[0][0];
if (int_ptr != NULL) {
printf("ptr1 = 0x%x
", int_ptr);
*int_ptr = 100;
}
int_ptr = sample_ptr[1].ptr_table[0][0];
if (int_ptr != NULL) {
printf("ptr2 = 0x%x
", int_ptr);
*int_ptr = 100; // crashed here!
}
}On Linux the same code ran without issues for two years, while on the newly configured Windows environment it crashed. The key difference is that Linux zero‑initializes newly allocated memory, whereas Windows does not.
Changing the allocation to sample* sample_ptr = new sample[10](); forces value‑initialization, making the memory zeroed on both platforms and eliminating the crash.
Understanding the Different Forms of new
In C++ the new operator can be used in several ways, each with distinct initialization semantics:
int* p1 = new int; // default‑initialized (indeterminate value)
int* p2 = new int(); // value‑initialized (zero)
int* p3 = new int(1); // value‑initialized with 1
A* p4 = new A; // default‑initialized (calls default ctor)
A* p5 = new A(); // value‑initialized (calls default ctor, then zero‑initializes members if no user‑provided ctor)
A* p6 = new A[10]; // default‑initialized array of objects
A* p7 = new A[10](); // value‑initialized array of objectsAccording to the C++ standard (see C++ Primer, Fourth Edition , §5.11), new A performs *default initialization* while new A() performs *value initialization*. For built‑in types, default initialization leaves the memory uninitialized, whereas value initialization zeroes it. For class types, default initialization invokes the default constructor; if the class has no user‑defined constructor, the members remain uninitialized unless value initialization is used.
The practical effects are:
p1 points to an int with an indeterminate value.
p2 points to an int initialized to 0.
p3 points to an int initialized to 1.
p4 points to an instance of A constructed with the default constructor; members are uninitialized unless the constructor sets them.
p5 points to an instance of A where, if A has a user‑defined default constructor, that constructor runs; otherwise the object’s members are zero‑initialized.
p6 and p7 behave like p4 and p5 respectively for each element of the array.
In the original sample struct there is no user‑defined constructor, so new sample[10] leaves the ptr_table members uninitialized. On Linux the operating system zeroes the memory for security reasons, so the pointers happen to be NULL and the program does not crash. Windows does not zero the memory, so the pointers contain garbage and dereferencing them leads to a crash.
Further experiments show that allocating an array of built‑in types without parentheses yields indeterminate values, while using parentheses forces zero‑initialization:
int size = 10;
{
int* p1 = new int[size];
for (int i = 0; i < size; i++)
p1[i] = i + 200;
// prints the initialized values
delete[] p1;
}
{
int* p1 = new int[size];
for (int i = 0; i < size; i++)
printf("%d\t", p1[i]); // prints garbage on many systems
delete[] p1;
}**Answers to the raised questions**:
The differing behavior of new sample[10] on Windows and Linux stems from the operating system’s memory‑zeroing policy, not from the C++ language itself. Linux zeroes freshly allocated pages for security, while Windows may leave them uninitialized. new sample[10] performs default initialization (leaving built‑in members uninitialized), whereas new sample[10]() performs value initialization, which zeroes built‑in members when no user‑defined constructor exists.
**Conclusion**: Relying on the OS to initialize memory is unsafe. Code should explicitly initialize variables, and developers must understand the distinction between default and value initialization when using new in C++.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
ITPUB
Official ITPUB account sharing technical insights, community news, and exciting events.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
