The call to std::list<T>::end() is unlikely to be a big efficiency issue and probably just reads a single value. However, you'd give the compiler a hint that it isn't meant to change by storing it a variable. For other containers a computation may be involved in addition to reading a base address which is a bit more involved. Still nothing dramatic but possibly worth avoiding.
Note, however, that it may also change the semantic of the loop: If the body of the loop may append elements, the former end may move. Interestingly, I don't find any specific requirements in the standard stating whether std::list<T>::end() may change when inserting elements into the container (I can imagine implementations where it does change as well as some where it doesn't; most likely it doesn't change, though). If you want to get guaranteed behavior when also modifying the list, you might very well call list.end() in every iteration.
BTW, there is a bigger performance concern I'd have about using iterator++ instead of ++iterator, especially this is really what the author used in the book. Still, this is a micro optimization like storing the result of list.end() but one cheap to do.