【发布时间】:2020-04-30 19:21:04
【问题描述】:
我有这样的代码:
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 指的是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 提出了相关问题:
【问题讨论】:
-
"如果
const被删除,它会正常工作。" 我想这给我们带来了一个明显的问题:当你声明时你 是认真的数据是const?因为如果你想改变一个东西,那么这意味着当你宣布所说的东西是const时你实际上并不认真。因为const意味着你不能改变它。你自相矛盾,而 C++ 并不真正喜欢你这样做。 -
我不希望个别成员被修改。我不介意整个对象被替换。不幸的是,C++
const将这两个概念结合在一起。 (这确实承认另一种选择,使用非常量不可变包装器(例如std::unique_ptr<Data const>,指针本身是非常量的)。但这在访问时增加了令人讨厌的间接性,所以我认为它更糟。)