My question is if containers like vector, set, queue, map, multimap, etc. provide their standard thread-safety guarantees (i.e. that concurrent threads may access const members, etc.) regardless of how a thread accesses the contained object.
No, not "regardless". Given "concurrent threads [accessing] const
members" [of the container], they can get const access to stored elements, but the container doesn't make it possible to do anything to the objects that wouldn't be legal if the objects were e.g. local variables - i.e. you can't call methods that affect mutable or static variables in a thread-unsafe way.
To put it simply: if you lock, say, a map for read, can you safely (as far as the map is concerned) modify the contained objects (in this case the value) as long as you're not inserting or deleting items or otherwise calling non-const methods on the map?
If by "lock a map for read" you mean your program has a separate read/write-lock and gets "reader" lock state before accessing the map, then no - you can't modify the contained objects if other readers may be accessing them. To make that safe, you need a mutex around the map usages, just as you would if the threads were operating on a local variable.
Examples
Below, a blank line separates examples, and the first and second columns list commands from two threads that may execute in either order or concurrently. Note that just because something is "safe" to execute doesn't mean the update will be visible in other threads until some explicit memory barrier or cache-flushing operation is done - it depends on your hardware: "proper" mutex/rwlocks etc. tend to take care of that.
class X { int n_; std::string s_; } x;
std::vector<X> v = ...;
std::map<int,X> m = ...;
thread 1 thread 2 safe?
v.push_back(...); ++v[0].n_; Precondition: 1 <= size() < capacity()
(i.e. safe iff v[0] can't be moved)
v.some-const-member(); v.another-const-member(); YES - e.g. [n], find(), begin()
v[0].s_ = "hi"; std::cout << v[0].s_; NO - as for any string var
v[0].s_.size(); std::cout << v[0].s_; YES - as for any string var
rw_lock.r_lock() LOCKED
iterator i = m.find(7); rw_lock.w_lock() BLOCK
rw_lock.r_unlock() ....
LOCKED
std::cout << i->second; m.insert(...); YES - insert can't invalidate i
i->second.n_ += 3; m.find(7).n_ -= 3; NO - as per any int var