我开始使用std::string
作为我的映射键,因为我映射中的每个项目都可以单独由字符串唯一标识。
然后我意识到,根据另一个参数以某种方式对地图进行排序对我来说会更有用,所以我在我的键中添加了一个称为优先级的int
来帮助排序。这个想法是我迭代地图并首先处理更高优先级的项目。我现在有以下用户定义的struct
作为我的映射键:
struct MyKey {
// key data
std::string addr;
int priority;
// constructor
MyKey(const std::string & s, const int p)
: addr(s), priority(p) {}
// overloaded operator
bool operator<(const MyKey &that) const {
// same key if addr is the same
if (that->addr == this.addr)
return false;
// not same key so look at priorities to determine order
if (that.priority < this->priority)
return true;
if (that.priority > this->priority)
return false;
// priorities are the same so use the string compare
return (that.addr > this->addr);
}
};
地图排序似乎工作正常,当您要迭代地图时,添加新项目时,它们会自动输入到预期位置。例如,对于std::string
值的映射:
std::map<myKey, std::string> myMap;
myKey key1 = myKey(std::string("key1"), 1);
myKey key2 = myKey(std::string("key2"), 2);
myKey key3 = myKey(std::string("key3"), 3);
myKey key4 = myKey(std::string("key4"), 4);
myMap[key1] = std::string("value1");
myMap[key2] = std::string("value2");
myMap[key3] = std::string("value3");
myMap[key4] = std::string("value4");
将在各自的索引处产生以下映射键值对:
[0] { addr = "key4", priority = 4 }, { "value4" }
[1] { addr = "key3", priority = 3 }, { "value3" }
[2] { addr = "key2", priority = 2 }, { "value2" }
[3] { addr = "key1", priority = 1 }, { "value1" }
然而。。。在修改映射中已经存在的键的现有优先级时,我遇到了问题。
在这种情况下,find()
和[]
(关于std::map
(不能按照我希望它们的方式工作:
myKey modified_key1 = myKey(std::string("key1"), 5);
// problem 1 - this does not return iterator to "key1",
// but instead to end of the map
auto & foundKey = myMap.find(modified_key1);
// problem 2 - this adds a brand new item to the map
myMap[modified_key1] = std::string("value1");
如上所述problem 2
后,我将一个新项目添加到地图中,其addr
与现有项目相同。新项目似乎已根据新的(修改的(priority
添加到预期位置,但要更新的现有项目仍保持原样。所以我最终在地图中有 2 个项目,它们的键中具有相同的addr
:
[0] { addr = "key1", priority = 5 }, { "value1" }
[1] { addr = "key4", priority = 4 }, { "value4" }
[2] { addr = "key3", priority = 3 }, { "value3" }
[3] { addr = "key2", priority = 2 }, { "value2" }
[4] { addr = "key1", priority = 1 }, { "value1" }
这对我来说是一个问题,因为我想仍然依赖于地图项键的addr
是唯一的概念。
我想要的是地图意识到它已经有一个具有相同键的项目(或者更确切地说是相同的键addr
(,并相应地重新排序该项目。
我尝试将比较函子作为映射定义的一部分进行试验,并在运算符==
重载键,但同样的问题仍然存在。
我错过了什么,或者我应该以不同的方式处理这个问题?
问题是您的比较运算符实现不正确,它没有提供严格的弱排序,因此std::map
的行为未定义,假设您有 3 个MyKey
对象:
MyKey mk1{ "a",3 }, mk2{ "b", 2 }, mk3 { "a", 1 };
mk1 < mk2 -> true as 3 > 2
mk2 < mk3 -> true as 2 > 1
mk1 < mk3 -> false as addr is the same, but must be true
现场示例
我认为你的问题不容易用std::map
解决.可能的解决方案是使用带有地址的boost::multi_index
作为一个索引,将优先级用作另一个索引。更改现有元素的优先级boost::multi_index
提供了替换数据的方法。
而不是MyKey
您可以使用std::tuple<int, std::string>
,它为您定义了关系运算符:
using MyKey = std::tuple<int, std::string>;
为您节省十几行。
不能修改任何关联容器中元素的键。相反,您需要使用旧密钥删除元素,然后使用新密钥重新插入它。