The general answer is const T &, which I prefer to write T const & because it composes correctly in the next paragraph.
For T=string*, we get string * const &, or a reference to a constant pointer to a string.
This means you can't mutate the list element (via a const_iterator) by pointing it to a different string, but you can indirectly mutate the list by altering the string to which it points.
You can read the definitions of std::list<T>, but it isn't as clear as it could be about the iterator behaviour - it works out like so:
std::list<T>::value_type is the same as T
- so
std::list<string*>::value_type is string*.
std::list<T>::const_iterator models a const LegacyBidirectionalIterator
LegacyBidirectionalIterator is a LegacyForwardIterator which must satisfy LegacyInputIterator
LegacyInputIterator must support the expression *i returning type reference
and finally, from the LegacyForwardIterator we rather skipped over
(where T is the type denoted by std::iterator_traits::value_type)
which is how we get from the type named reference to the const T & we started with.
string const *- `constant pointer to non const data