如何强制调用const find



我正在用c++ 11中的std::map编码。

我读过这个链接,它告诉我c++ 11标准保证const方法对容器的访问在不同线程中是安全的。

根据我的理解,这意味着std::map::size()是线程安全的,因为这个函数被声明为size_type size() const noexcept;

现在我想调用函数std::map::find线程安全。例如,if (mp.find(xxx) != mp.end()) {}.但是,find有两个版本,一个是const,另一个是非const:https://en.cppreference.com/w/cpp/container/map/find.

那么我如何知道哪个版本的find正在调用?如何强制调用const-versionfind以获得线程安全的代码?

我知道std::map::cend()有一个const版本,if (mp.find(xxx) != mp.cend()) {}会像预期的那样工作吗?

你可以用std::as_const

if(std::as_const(mp).find(xxx)==mp.end())
{
//do your thing
}

一般规则是const是多读器安全的,而其他操作则不是。

但是也有一些例外。基本上,返回迭代器或对现有对象的引用(没有创建对象)的非const操作也被认为是"读取器"。操作,并且是多阅读器安全的。使用非const_iterator返回值来修改底层数据通常会有问题,但在许多容器中,这样的修改只会在另一个操作正在访问的同一元素上引起争用。

if (map.find(foo) == map.end())

可以安全地与其他只读取map对象的操作一起使用。

仍然有很好的理由调用const操作。在c++17中有std::as_const,允许

if (std::as_const(map).find(foo) == map.cend())

只调用map上的const方法。您可以轻松编写自己的as_const:

template<class T>
std::add_const_t<T>& as_const( T& t ) { return t; }

(在c++11中,您需要展开add_const_t)。std版本增加了

template<class T>
void as_const( T const&& t ) = delete;

阻断一些相对病理的病例

…当考虑线程安全时,要意识到它是一个关系属性。两个操作相对线程安全。

std容器的情况下,您必须考虑操作如何读写容器本身,它读取或写入哪些元素。虽然标准更具技术性,但这将使您直观地了解允许的内容。

只读取容器并返回迭代器或元素引用的方法有时是非const,但它们本身只读取容器。

修改或读取元素的操作通常与其他修改该元素的操作是互斥的。在矢量中,您可以自由地读取v[0] = 77;,而另一个线程读取v[7]而没有同步(在vector<bool>之外)。但是当您的.push_back容量不足时,您需要与其他每一次读取同步。

这可能是反直觉的。如果要对容器进行无同步访问,请小心,并阅读文档。直觉只是第一步。

如果mpconst,那么find将是const版本。然而,调用非const版本在线程安全方面与调用const版本没有什么不同,如果您实际使用返回的迭代器对保存值进行修改(如果您仔细阅读您链接的答案,它包含此区别),则会出现差异。

注意,只有调用多个const方法是线程安全的,同时从另一个线程调用非const方法是不安全的。