像std :: vector&&朋友(我实际上正在使用QList)抛出一个可捕获的异常,或者如果一个线程在另一个线程正在读取它时尝试写入容器,它是未定义的行为:
std::vector<std::string> stuff;
另一个帖子中的非关键任务(例如拼写检查):
try {
for (std::string& s : stuff) {
//do stuff with s
}
} catch (...) { // Handle all exceptions
//bail out of task
}
主线程:
stuff.erase(std::remove(someIterator), stuff.end());
所以你可以看到这里会有一个场景,它可能有一个无效的迭代器,并且会在读取线程中抛出异常 - 这将被捕获并且只是保释出任务。
但这只是一种情况 - 我可以依赖从这些容器中抛出可捕获的异常,这样我就不需要用互斥锁保护向量或字符串了吗?或者是否会有一些情况可以解除引用nullptr(或其他东西)并导致SEH异常 - 即我无法捕获并继续的东西。我认为答案是它可能依赖于实现,并且最有可能导致未定义的行为,但我想我会问这个问题。
答案 0 :(得分:8)
一般来说,你不能指望访问一个无效的迭代器,抛出任何类型的异常。结果是未定义的行为:调用可能会抛出,它可能会崩溃,它可能会工作多年然后再咬你,它可能会破坏程序中其他地方无关的东西。
标准禁止对标准库的对象和功能进行此类处理:
17.6.4.10/1:
如果从不同线程调用标准库函数可能引入数据争用,则程序的行为是未定义的。可能发生这种情况的条件在17.6.5.9中规定。
17.6.5.9/6:
通过调用标准库容器或字符串成员函数获得的迭代器操作可以访问底层容器,但不得修改它。 [注意:特别是,使迭代器无效的容器操作与与该容器关联的迭代器上的操作冲突。 - 结束记录]
大多数Qt函数同样不是线程安全的。
如果您需要在线程之间共享数据,请保护自己免受数据争用。除非文档说明,否则不要指望图书馆为你做这件事。
答案 1 :(得分:1)
使用无效的迭代器本身就是未定义的行为。它似乎没有像你想象的那样抛出异常。所以你的想法(除非我误解了)即使是愚蠢的也不会飞。
访问同一std :: object的数据竞争也是未定义行为的来源。
答案 2 :(得分:0)
AFAIK标准没有说明std :: vector等人的多线程行为。但实际上,每个人都将以最直接,最高效的方式实现事物,这意味着没有任何线程安全。
MSDN记录了他们实施STL的行为。我希望主流实现之间没有区别。仅供参考,MSDN文档的长和短是,如果您在其他线程中有读者并且容器正在被修改,则行为将是未定义的。