在std :: map中更改值的键

时间:2013-08-22 16:22:53

标签: c++ dictionary map stl key-value

我需要在std :: map中更改给定值的键。所以我写了这个方法:

bool alter_key(_Kty oldKey, _Kty newKey)
{
    std::map<_Kty, _Ty>::iterator it = this->find(newKey);
    if(it != end()) //can't replace because newKey is already been used.
        return false;

    it = this->find(oldKey);
    if(it == end()) // empty index.
        return false;

    _Ty value = it->second;
    this->erase(it);
    this->insert(std::pair<_Kty, _Ty>(newKey, value));
    return true;
}

它可以正常工作,但是可以优化此代码吗?

1 个答案:

答案 0 :(得分:3)

如果您需要加快特定操作,那么std::map可能不是容器的正确选择。话虽这么说,它也可能是正确的选择,所以下一个问题是在该功能中有什么优化,功能中的成本是多少?是查找吗?创建新元素的成本?

如果成本较高是复制数据,那么您可能需要考虑避免算法中的副本。而不是从容器复制到局部变量,然后执行额外的副本以插入目标,您可以跳过中间副本:

insert(std::make_pair(new_key,it->value));
erase(it);

如果value复制成本高,但可以移动(rvalue-reference移动,或者默认构造便宜,你可以交换内容),你可以利用它:

insert(std::make_pair(new_key,std::move(it->value)));
// alternatively in C++03, for example for large strings or std::vector<> values
value_type& x = *insert(std::make_pair(new_key,ValueType())).first;
swap(x,it->value);

请注意事情变得更加复杂,难以理解/维护。

您可以改进的另一件事是查找。目前,您对容器进行了三次查找:两次用于确定是否存在旧密钥和新密钥,另外三次用于插入。你可以减少它。如果您尝试插入并且密钥已经存在,则不会对其进行修改,因此您可以执行以下操作:

using std::swap;
iterator it = find(old_key);
if (it == end()) return false;
std::pair<bool, iterator> ins_res = insert(std::make_pair(new_key,ValueType()));
if (!ins_res.second) return false;
swap(it->second,ins_res.first->second); // swap contents
erase(it);

但是,考虑一下std::map是否是您的数据结构的正确选择......例如,如果查找很昂贵并且排序不重要,那么std::unordered_map因为它可能具有更好的查找性能