The simple answer here is that as the developer, you are in charge of collision detection. But "who is responsible" is not really an important question when it comes to collision detection. The important question is: "How many pairs of objects must be tested for collision each frame?"
Now, in a shmup most collisions take place between a bullet/munition and a player/enemy unit. Collisions between two munitions and collisions between two units are usually ignored. This means all we need to do is keep two lists of objects - one for units and one for munitions. In fact, you can probably split up objects into even more groups, reducing the number of potential collisions further. For instance, you could separate player munitions from enemy munitions and player units from enemy units, since player munitions will probably only ever cause damage to enemies, and enemy munitions will only cause damage to players.
With this system, there's probably no optimization required. Each object in one list can be tested against every object in the other. If we have N
units and M
munitions then we end up doing N*M
collision checks. We may have a very large M
, on the order of several hundred or more, but N
is probably on the order of 3-6, perhaps up to a dozen.
If you're working on mobile, or you have so many objects that you're still having performance issues, or you need more flexibility to allow collisions between objects of the same type, then chances are you'll want to use a broad-phase algorithm, utilizing a space partitioning data structure to reduce the set of potential collision-pairs before doing the actual collision-detection. You can reinvent the wheel yourself here if you like, but a far less painful approach is to simply use a physics library like Box2D or Bullet and let it take care of the collision detection for you.