STL不保证其集合的线程安全。但我想知道以下代码是否真的有效。
一个线程通过调用[]运算符调用地图m上的非const运算,但是使用地图上已存在的键。据我所知,这只是调用find()并返回对gcc中迭代器的引用。另一个线程同时将const迭代器保存到m。
问题是:断言会失败吗?
void doBracket(std::map<int, int>& m) {
const auto& val = m[0];
std::cerr << val << std::endl;
}
void doIter(const std::map<int, int>& m){
auto zeroIter = m.find(0);
auto oneIter = m.find(1);
auto twoIter = m.find(2);
assert(zeroIter->second == 0);
assert(oneIter->second == 1);
assert(twoIter->second == 2);
}
int main() {
std::map<int, int> m = {{0, 0}, {1, 1}, {2, 2}};
std::thread mutateThread {doBracket, std::ref(m)};
std::thread constThread {doIter, std:ref(m)};
mutateThread.join();
constThread.join();
}
这是stl_map的作用:
operator[](const key_type& __k)
{
// concept requirements
__glibcxx_function_requires(_DefaultConstructibleConcept<mapped_type>)
iterator __i = lower_bound(__k);
// __i->first is greater than or equivalent to __k.
if (__i == end() || key_comp()(__k, (*__i).first))
//handle this case
return (*__i).second;
}
答案 0 :(得分:1)
看来你已经确定了一个可以超越标准的地方,了解实施情况。但是,与使用find()
代替operator[]()
的保证安全方法相比,此方法没有优势。
补充工具栏:我个人认为std::map::operator[]()
几乎无用。我总是希望使用find()
,insert()
或其他内容。
答案 1 :(得分:1)
如果你看一下http://www.cplusplus.com/reference/map/map/operator%5B%5D/,就会说map :: operator []:
迭代器有效期
没有变化。
数据竞赛
访问容器,并可能进行修改。 该函数访问一个元素并返回一个可用于修改其映射值的引用。同时访问其他元素是安全的。 如果函数插入一个新元素,则同时迭代容器中的范围是不安全的。
根据这一点,唯一可能不安全的情况是“如果函数插入新元素,则同时迭代容器中的范围”。由于您没有进行任何插入,因此结论必须是您的代码是安全的。