konev13 said:
If you have a single struct with a collection of pointers that you pass around globally, then theres no difference than having a single instance that you can access globally vs having to pass around the pointer to every object.
There is at least one difference, even in the case that the service locator only ever points at the same things at every call site. Passing the “structure of globals”/"service locator" around instead of having extern globals means that only functions that actually NEED to talk to the globals will be able to do so, and the fact that they do so is explicit. Ideally, you wouldn't even pass all of the services around like this; you would instead pass JUST the services you need around. The services may still be “global” in lifetime, but they wouldn't be “global” in the sense that everything in the entire program could access them from anywhere. This can make the code easier to understand and enforces a bit of discipline.
Also, while the typical use case for having the service locator point to different objects at different call sites would be mock/fake objects in tests, there are others. You may for instance have double-buffered game state so that your gameplay code and rendering code can run at the same time on different frames. The service locator makes this easier; to do this with actual global variables, you need to start getting into using thread-local storage and other such platform-specific things.