照着抄会直接报错, 后来我排查了很久才发现问题所在
问题排查
报错原因是这样的(手动分行)
No viable conversion from returned value of type
'std::_List_const_iterator<std::_List_val<std::_List_simple_types<std::pair<int, std::basic_string<char>>>>>'
to function return type 'typename list<bucket_value>::iterator'
(aka '_List_iterator<_List_val<std::_List_simple_types<std::pair<int, std::basic_string<char>>>>>')
把第二行和第四行的类型提取出来, 可以看到大概意思应该是说不能把const的迭代器转为非const的迭代器
'std::_List_const_iterator<std::_List_val<std::_List_simple_types<std::pair<int, std::basic_string<char>>>>>'
________________'_List_iterator<_List_val<std::_List_simple_types<std::pair<int, std::basic_string<char>>>>>'
首先, 查看list的源码可以看到list::begin()是有两个版本的(end()也一样)

区别是一个返回iterator, 另一个返回const_iterator且函数后面有const
当同样在加了const的成员函数里调用begin()会返回第二个版本, 即只读迭代器const_iterator
而书里的源码是这样的
using bucket_data = list<bucket_value>;
using bucket_iterator = typename bucket_data::iterator;
bucket_iterator find_entry_for(Key const &key) const
{
return find_if(data.begin(), data.end(),
[&](bucket_value const &item){return item.first == key;});
}
find_entry_for()函数声明后面加了const, 于是里面的data.begin()和data.end()会调用上面的第二个版本, 即返回const_iterator, 进而find_if()找到的迭代器也会是const_iterator
然而函数声明的迭代器却是读写迭代器(iterator), 无法从只读迭代器(const_iterator)转换为读写迭代器(iterator), 从而报错
验证如下
#include<bits/stdc++.h>
using namespace std;
class A
{
public:
int get_value() const
{
return 1;
}
int get_value()
{
return 2;
}
};
class B
{
A member_a;
public:
void print_A_value()
{
A local_a;
printf("member_a:%d\n", member_a.get_value());
printf(" local_a:%d\n", local_a.get_value());
}
void print_A_value_const() const
{
A local_a;
printf("add const member_a:%d\n", member_a.get_value());
printf("add const local_a:%d\n", local_a.get_value());
}
};
int main()
{
B b;
b.print_A_value();
b.print_A_value_const();
return 0;
}
member_a:2
local_a:2
add const member_a:1
add const local_a:2
可以看到其中第三行输出了1
从中可以看到触发是有条件的, 操作的变量只能为成员变量, 不能是局部变量(全局变量也不行)
从而验证了上面对报错原因的猜测(会根据函数声明有无const, 进而调用不同的成员变量重载函数)
我的修改方法如下, 首先声明一个只读迭代器类型bucket_const_iterator
再为find_entry_for添加一个不加const的重载版本
using bucket_iterator = typename bucket_data::iterator ;
using bucket_const_iterator = typename bucket_data::const_iterator ;
bucket_const_iterator find_entry_for(Key const &key) const
{
return find_if(data.begin(), data.end(),[&](bucket_value const &item){return item.first == key;});
}
bucket_iterator find_entry_for(Key const &key)
{
return find_if(data.begin(), data.end(),[&](bucket_value const &item){return item.first == key;});
}
同时发现3个接口函数里只有value_for()声明里加了const, 会调用加const版本的find_entry_for()
且value_for()内部不需要修改found_entry, 所以修改局部迭代器变量声明为bucket_const_iterator,
其他函数则调用不加const版本的获取读写迭代器bucket_iterator
Value value_for(Key const&key,Value const&default_value) const
{
shared_lock lock(m);
bucket_const_iterator found_entry= find_entry_for(key);
return (found_entry==data.end())?default_value:found_entry->second;
}
最后成功运行!
博客指出《C++并发编程实战》中文版(第二版)第201页的threadsafe_lookup_table代码存在一个问题,导致编译报错。错误源于在const成员函数中,调用了返回const_iterator的begin()和end(),但后续操作需要读写迭代器。通过分析源码,博主揭示了解决方案,即定义新的只读迭代器类型,并为find_entry_for添加非const重载版本,同时调整接口函数中迭代器的使用,从而避免从const_iterator到iterator的非法转换。
7604

被折叠的 条评论
为什么被折叠?



