You must protect all access to the list in order to be safe. While reading from a list without a lock will not corrupt the list, if the list is modified while another thread is reading from it, either thread could become corrupt (i.e. crash, or produce incorrect results).
You must hold the lock for the entire span of code that you expect the contents to be stable for. If another thread can erase or reorder any element at any time, then this includes any time you have live iterators to its contents. If there are restrictions as to which threads can manipulate which elements, the locking requirements can be relaxed with respect to holding live iterators.
Using std::lock_guard can help make sure you manage the lock correctly. Just create an instance of it at the beginning of any scope that will manipulate your list, and at the end of the scope it will automatically unlock, even if the scope exits via exception.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…