首页 > 解决方案 > 使用迭代器替换地图中的常量项的方法

问题描述

我有这样的代码:

std::map<int, const Data> all_data;
// ...
bool OldDataIsBetter(Data const& oldData, Data const& newData) {...}
// ...
void AddData(int key, Data&& newData)
{
    auto [it, ok] = all_data.try_emplace(key, std::move(newData));
    if (!ok)
    {
        if (OldDataIsBetter(*it, newData)) return;
        it->second = std::move(newData);
    }
}

这不会编译,因为it->second引用了 a const Data,所以它的赋值运算符不能被调用。如果const被删除它工作正常。

上面的目的是insert_or_assign,除了如果一个项目已经存在,那么我需要比较旧项目和新项目,看看哪个“更好”。

声明地图元素类型的目的const是数据应该在地图中一次是不可变的——项目作为一个整体可以被替换,但不能被零碎地修改。

我可以通过重新分配给容器来“修复”上述问题:

all_data[key] = std::move(newData);

(实际上结果与 . 有相同的问题const。)

或者通过擦除并重试 emplace:

all_data.erase(it);
all_data.emplace(key, std::move(newData)); // should never fail

但是这些看起来都不优雅,因为我已经有一个迭代器指向应该被替换的项目,并且上面两个都忘记了,然后再次搜索。

有没有更好的方法来完成这个替换?


来自聊天线程的 TLDR 提出了相关问题:

标签: c++stlc++17stdmap

解决方案


const意思是不可变的,不是部分可变的。如果您const在对象声明上使用(这是您在插入const该模板参数时所做的事情),C++ 相信您是认真的。它会让你坚持下去。

const Data非首发也是如此。

根据您的问题,我推测Data有一些功能可以设置其状态的某些部分,并且您不希望用户调用所述功能。但是您希望用户能够覆盖该值。

做到这一点的方法是提供一个包装Data实例的对象类型,允许从Data对象进行赋值。这个包装器将提供所提供的访问器的const版本Data。但是该类型不提供 . 的非const修饰符Data


推荐阅读