I almost voted that this is too opinion-based, but on thinking on it further, I think it's safe to say with some sureness that the second option presented is just bad. Don't do that.
Among other things, it means that any components which must create objects needs a dependency on another component, potentially a different component for each type of thing it creates.
More complex games do delay the entire creation of the object. This is because you can't just call new Foo in complex engines, especially component-based ones. You need a more intricate resource system that can clone objects from blueprint or the like, so you end up doing something like:
pGameWorld->SpawnObject(m_BlueprintHandle);
The actual creation and initialization of the object may happen immediately or be delayed until next frame (or even later, for engines that allow asynchronous on-demand loading of resources). It's also common to have initialization parameter structs for passing in position, velocity, orientation, and other common per-instance data, like:
SpawnData spawn; spawn.position = Vector2d(x, y); spawn.blueprint = m_BlueprintHandle; spawn.baseName = "BlueMissile"; spawn.creator = this; pGameWorld->SpawnObject(spawn);
Or it might take several different structs, some parameters and some structs, or so on. There's also engines that use serialization systems to set parameters, so you see things like:
MemoryParameterStream params; params.write("position.x", x); params.write("position.y", y); pGameworld->SpawnObject(m_BlueprintHandle, params);
This can be combined with the previous approach to handle both common parameters (position, etc.) and any component-specific parameters that you need to set in less common circumstances.
How and when the game world actually creates the request object is abstracted away. It might return a handle to a temporary object, something like:
Handle GameWorld::SpawnObject(Handle blueprintHandle) { Handle newHandle = AllocateEmptyObject(blueprintHandle); m_PendingInitializations.push_back(newHandle); return newHandle; } // elsewhere m_ChildHandle = pGameWorld->SpawnObject(m_BlueprintHandle);
Just so that the creator can hold onto references to the object if needed for later use. This is not uncommon for some attack systems that kill or despawn certain attack objects (bullets, laser beams, etc.) when the weapon or attacker that fired them dies, for instance.
In the end, your first suggestion is simple and Just Works(tm) for most simple games. Do that. Do not do your second option; it's more complicated with no benefits and just adds more coupling and dependencies.