I have a class Bullet that takes several arguments for its construction. However, I am using a dynamic memory array to store them. I am using C++ so i want to conform to it's standard by using the new operator to allocate the memory. The problem is that the new operator is asking for the constructor arguments when I'm allocating the array, which I don't have at that time. I can accomplish this using malloc to get the right size then fill in form there, but that's not what i want to use :) any ideas?
pBulletArray = (Bullet*) malloc(iBulletArraySize * sizeof(Bullet)); // Works
pBulletArray = new Bullet[iBulletArraySize]; // Requires constructor arguments
Thanks.
You can't.
And if you truly want to conform to C++ standards, you should use
std::vector
.FYI, it would probably be even more expensive than what you're trying to achieve. If you could do this,
new
would call a constructor. But since you'll modify the object later on anyway, the initial construction is useless.The way C++ new normally works is allocating the memory for the class instance and then calling the constructor for that instance. You basically have already allocated the memory for your instances.
You can call only the constructor for the first instance like this:
new((void*)pBulletArray) Bullet(int foo);
Calling the constructor of the second one would look like this (and so on)
new((void*)pBulletArray+1) Bullet(int bar);
if the Bullet constructor takes an int.
If what you're really after here is just fast allocation/deallocation, then you should look into "memory pools." I'd recommend using boost's implementation, rather than trying to roll your own. In particular, you would probably want to use an "object_pool".
Then populate pBulletArray:
Just don't forget to free the memory using delete afterwards.
1)
std::vector
A
std::vector
really is the proper C++ way to do this.2)
new []
operatorIt is also possible to do this with
new
, but you really shouldn't. Manually managing resources withnew
/delete
is an advanced task, similar to template meta-programming in that it's best left to library builders, who'll use these features to build efficient, high level libraries for you. In fact to do this correctly you'll basically be implementing the internals ofstd::vector
.When you use the
new
operator to allocate an array, every element in the array is default initialized. Your code could work if you added a default constructor toBullet
:Then, when you have the real data for a
Bullet
you can assign it to one of the elements of the array:Note the use of
unique_ptr
to ensure that proper clean-up occurs, and that it's exception safe. Doing these things manually is difficult and error prone.3)
operator new
The
new
operator initializes its objects in addition to allocating space for them. If you want to simply allocate space, you can useoperator new
.(Note that the
unique_ptr
ensures that the storage will be deallocated but no more. Specifically, if we construct any objects in this storage we have to manually destruct them and do so in an exception safe way.)bullets
now points to storage sufficient for an array ofBullet
s. You can construct an array in this storage:However the array construction again uses default initialization for each element, which we're trying to avoid.
AFAIK C++ doesn't specify any well defined method of constructing an array without constructing the elements. I imagine this is largely because doing so would be a no-op for most (all?) C++ implementations. So while the following is technically undefined, in practice it's pretty well defined.
That will construct elements of the array without using the default constructor. You don't have to construct every element, just the ones you want to use. However when destroying the elements you have to remember to destroy only the elements that were constructed.
The above is a pretty simple case. Making non-trivial uses of this method exception safe without wrapping it all up in a class is more difficult. Wrapping it up in a class basically amounts to implementing
std::vector
.4)
std::vector
So just use
std::vector
.It's possible to do what you want -- search for "operator new" if you really want to know how. But it's almost certainly a bad idea. Instead, use std::vector, which will take care of all the annoying details for you. You can use std::vector::reserve to allocate all the memory you'll use ahead of time.