i is (most likely) an iterator. This iterator appears to be assocated with a string. The -> directive allows you to "dereference" the iterator and then fetch a member. An iterator "acts" as a dummy pointer (when in actuality, it just wraps around one most of the time) which is why the syntax is like this.
empty() checks for whether or not the string is empty... doesn't really make sense for it to be checked each iteration since the iterators would become invalid after the string changes anyways.