Add begin and end iterators to the ModuleList so we can use range-based for loops without locking from beginning to end. This is what makes it different from the Modules() method which returns a LockingAdaptedIterable but also means the burden of correctness is on the caller.
I'm not sure if this distinction matters, but it preserves the semantics of the code that is currently using GetModuleAtIndex directly from inside a classically indexed for loop.
FWIW, std::iterator is deprecated since C++17 - probably best not to add new uses of it. (I think the idea is that the typedefs that std::iterator provides are no longer needed because of auto/decltype/etc, but I might be wrong there (would have to check the iterator concepts specifications))
If you need some utility help with implementing an iterator, llvm's iterator_facade_base might help by allowing a fairly minimal implementation to autogenerate various symmetric members, etc.