Currently the only solution that comes to mind, is to preallocate some storage. Instances are then being created using placement new syntax. I could still use pointers but in a DOD manner.
That would work (though waste a little memory), but the question remains: Why do this?
(And yes, you can do it without wasting any memory using one of two different ways, but one of those ways is extra slow, and the other is extra silly if you look at the bigger picture of your architecture).
If you are trying to keep everything in a single array, then it seems like you are trying to do it for performance reasons... but if for performance reasons, why are you trying to cram multiple different types at that low level?
Here's an interesting thing about components: They mostly don't share data, and they mostly don't share behavior. So why cram them polymorphically into the same interface, to pretend that they are mostly the same when they mostly aren't? Over generalization of code can create problems, just as under generalization can (though they create different types of problems).
Worse, performance-wise, is that even if you are accessing them as if they are the same, you'll still end up doing something like this:
void UpdateAllPhysics()
{
for(every component) //10,000 components
{
if(is physics component) <-- slow branch
{
physicsComponent->UpdatePhysics(); //Only actually using 1000 of the 10k components.
}
}
}
And repeat that for every different type of component. This anti-pattern of un-conforming your types would occur far more often than the iterating over the conforming interface.
That's not how it's supposed to be done. You are putting too much logic into the components (slowing them down, though keeping the design simple), and then trying to cram the components into a common interface (slowing them down and convoluting the architecture), which you'll then have to un-cram to operate on the specific component types again.
If someone mentions 'components' and 'virtual functions' in the same sentence, they're (probably) doing it wrong.
Components should be data only. Systems hold the logic that operate on the data. Entities are practically there in concept only, usually being nothing more than an ID that shows what components of different types in different systems logically belong together to create the behavior your game is wanting to present.
ECS = Entities. Components. Systems
From what little I'm hearing of you describing your architecture, I get the impression you're neglecting the 'Systems' part.
Basically, normal C++ polymorphism and contiguous blocks of memory are almost antithesis of each other, being at opposite ends of abstraction. Putting them together sounds like you are having difficulty figuring out what level of abstraction this ECS sub-module of your project belongs in.
And if you are working at the level of contiguous blocks of memory, you probably want to re-read the Typical C++ Bullshit series of slides.
Note:
- I love C++
- I love polymorphism
- I love templates and reducing code redundancy
- I love contiguous blocks of memory
- I love performance and optimization
- I love abstraction and simplification
The key, though, is the right tool at the right time. I may be wrong, but I'm getting the impression you picked up the wrong tool to solve your current problem.