C++ set迭代器调用非const成员报discards qualifiers错误怎么解决
问题根因分析
- 你的错误和lambda、lambda的
mutable关键字完全无关,核心原因是std::set的迭代器本质是const迭代器:C++11之后,
std::set<T>::iterator就是std::set<T>::const_iterator的别名。因为set是有序关联容器,修改元素的排序键会破坏容器的有序性,所以标准禁止直接通过迭代器修改元素,所有迭代器返回的都是const T&类型的引用。 - 你给lambda加
mutable没有生效的原因:mutablelambda的作用是允许修改lambda自身捕获的按值存储的成员变量,你这里是按指针捕获this,无论lambda是否是mutable,都不影响this指向的core对象的常量性,也不改变set_of_S.begin()返回const迭代器的事实。 - 为什么直接修改
it->c不报错:因为S::c被声明为mutable,const对象的mutable成员允许直接修改;但你调用的set_c()是非const成员函数,const对象无法调用非const成员函数,这才是编译错误的直接来源。
合规的解决方案(不需要修改
S类的原有定义) 你可以用C++17引入的std::set::extract接口安全修改set中不参与排序的字段,这个操作不会触发重排序,也不会产生未定义行为:
void set_fn() { f = [this]() { auto it = set_of_S.begin(); // 取出节点,脱离set之后可以修改元素 auto node = set_of_S.extract(it); node.value().set_c(); // 再插回set,因为没有修改参与比较的a、b字段,不会触发排序调整 set_of_S.insert(std::move(node)); }; }
关于给
set_c加const的合理性说明 如果S::c本身就是不参与对象等价判断、排序逻辑的附属字段,那么给set_c加const反而是符合语义的:这个成员函数不会修改对象的公开逻辑状态,仅仅修改了内部的可变附属字段,mutable关键字存在的意义就是支撑这类场景,并不会降低代码可读性。
内容的提问来源于stack exchange,提问作者OVOT
相关产品推荐
相关产品推荐

