我首先使用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
),并相应地对该项目进行重新排序。
我尝试将比较函子作为映射定义的一部分进行试验,并且还使键==
运算符重载,但是仍然存在相同的问题。
我想念什么,或者我应该以不同的方式来对待?
答案 0 :(得分:0)
您可以使用MyKey
代替std::tuple<int, std::string>
,而是为您定义关系运算符:
using MyKey = std::tuple<int, std::string>;
为您节省了十几行。
您不能修改任何关联容器中元素的键。相反,您需要使用旧键删除元素,然后使用新键重新插入。
答案 1 :(得分:0)
问题是您的比较运算符实现不正确,不提供strict weak排序,因此std::map
的行为未定义,可以说您有MyKey
的3个对象:
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
提供了替换数据的方法。