My question is about a code snanpshot from Scott Meyer’s Book “More Effective C++ 35 new ways …”
the code (parameter names are changed)
void * memory = operator new[] (10*sizeOf(MyClass));
MyClass * myArray = static_cast<MyClass*>(memory);
for(int i= 0; i<10; i++)
{
new (&myArray[i]) MyClass(params);
}
I am not familiar with this syntax. Even the operator new [] and the new (&myArray[i]) … Is there any resource that I can read detailed about that syntax, how they are working.
To understand this, you first need to understand how plain and simple
newworks. The usual syntax of anewexpression is something likenew T. When you use anewexpression, the following occurs:First, it calls an allocation function to obtain storage for the object. The allocation function simply has to return a pointer to some allocated storage large enough to fit the requested object. It does no more than this. It doesn’t initialize the object.
Next, the object is initialized in the allocated space.
A pointer to the allocated space (and now initialized object) is returned.
In the case of
new T, the allocation function is namedoperator new. When allocating an array, such asnew T[5], the allocation function is namedoperator new[]. Default definitions of these functions are provided in the global namespace. They each take a single argument of typestd::size_twhich is the number of bytes required. So when you donew T, the corresponding call is tooperator new(sizeof(T)), whereas fornew T[5],operator new[](sizeof(T)*5)gets called.It is, however, possible to pass more arguments to the allocation function. This is known as the placement new syntax. To pass more arguments, you use syntax like so:
new (some, arguments, 3) T, which will calloperator new(sizeof(T), some, arguments, 3). The list of arguments goes in parentheses betweennewand the type.In addition to the simple
operator new(std::size_t)and its array counterpart that are both provided by the implementation, there are also default definitions that take an extra argument of typevoid*. That is, they take a pointer to an object. These functions don’t actually allocate any space and simply return the pointer you gave them. So when you donew (some_pointer) T, it first callsoperator new(sizeof(T), some_pointer)which just returnssome_pointerback again and then it initializes the object in that space. This gives you a way to initialize an object in some already allocated space.So now we have these four pre-defined allocation functions (in fact, there are a few others and you’re free to define your own too):
So lets take a look at the code snippet you provided:
In the first line, we are calling
operator new[]directly to allocate some storage. How much storage? Well, enough for 10 objects of typeMyClass. This function returns a pointer to that allocated storage and you store it inmemory.After this, the
void*is cast to aMyClass*to allow you to index the allocated storage in blocks of sizesizeof(MyClass), i.e.myArray[0]will now point to the firstMyClassandmyArray[1]to the second.Now we loop through that array, calling placement new with the address of each uninitialized
MyClass-sized bit of allocated storage. In the first iteration, for example, this will call allocation functionoperator new(sizeof(MyClass), &myArray[0])which, as we saw before, does nothing but return the pointer you’ve given it. The new expression will complete by initializing aMyClassobject in this space and returning the pointer to it.So in summary, the code allocates some storage to fit 10
MyClassobjects (but doesn’t initialize them), then loops through eachMyClass-sized space in that storage, initializing an object in each of them.This demonstrates how you can initialize objects in already pre-allocated storage. You can reuse the same storage over and over with newly initialized objects.