template boy
template boy

Reputation: 10480

Zero-initialize data using value-initialized array

Will the following code correctly zero-initialize the memory returned from malloc?

#include <cstdlib>
#include <new>

int main()
{
    char* p = new (std::malloc(10)) char[10]{};
}

Upvotes: 7

Views: 174

Answers (2)

Edward
Edward

Reputation: 7100

Yes, it will zero-initialize memory because of the {} at the end of the line, as long as malloc doesn't fail from within the placement new. Here's an alternative version that more completely proves the point.

#include <iostream>
#include <cassert>
#include <new>

char mongo[10];

int main()
{
    for (int i=0; i < 10; ++i)
        mongo[i] = 'a';
    char *p = new (mongo) char[10]{};
    for (int i= 0; i < 10; ++i)
        assert(p[i] == '\0');
}

This program will run and print nothing because the mongo array (aliased by p) is explicitly cleared by the initialization of p. By contrast, if we omit the {} at the end of that line, the program will assert and terminate.

Note that in your version using malloc, you will have to explicitly destroy the object -- that's part of the responsibility that comes with placement new and among the few times in modern C++ where one must explictly call a destructor.

If, as in your particular case, you are allocating memory with malloc() you must issue a corresponding free(p) or your program will leak memory.

The elephant in the room

(Thanks, @TC, for pointing to the big gray thing!) Here's an explanation and example straight from the standard (section 5.3.4):

Example:

new T results in a call of operator new(sizeof(T)),

new(2,f) T results in a call of operator new(sizeof(T),2,f),

new T[5] results in a call of operator new[](sizeof(T)*5+x), and

new(2,f) T[5] results in a call of operator new[](sizeof(T)*5+y,2,f).

Here, x and y are non-negative unspecified values representing array allocation overhead; the result of the new-expression will be offset by this amount from the value returned by operator new[]. This overhead may be applied in all array new-expressions, including those referencing the library function operator new[](std::size_t, void*) and other placement allocation functions. The amount of overhead may vary from one invocation of new to another.

In other words, if you use placement new for a single object, everything is fine and there is no inserted overhead, but if you allocate an array via placement new, there may be overhead, and it might not even be the same size from invocation to invocation.

Upvotes: 7

T.C.
T.C.

Reputation: 137425

This is a very, very bad idea.

Currently, placement array new, like all array new expressions, is allowed to add an unspecified amount of overhead. There is no portable way for the program to know how many bytes this overhead is.

Therefore, unless the implementation's array allocation overhead for char[10] is zero, your code has undefined behavior.

If the pointer points to sufficient memory to accommodate all the array elements plus the unspecified overhead amount (and that's a very big if, since there's no portable way for you to be sure), then the expression will indeed zero-initialize the memory.

Upvotes: 5

Related Questions