通过迭代器修改集合中的元素

Change element in a set via iterator

本文关键字:元素 集合 修改 迭代器      更新时间:2023-10-16

我想更改集合(QSet)中的一个元素:

for(PSet::iterator pIt = P.begin(); pIt != P.end(); ++pIt)
  pIt->xp = 0;

编译器不允许我这样做("C3892: 'var':你不能给const变量赋值")。由于担心改变元素可能会破坏其在集合中的正确位置,set迭代器似乎总是常数。

在我的例子中,PSet是一组结构体,我为它们定义了自己的哈希函数:

struct P
{
  P(int id, const Data_t& data)
     :xp(_INFINITY_)
     ,id(id)
     ,data(data){}
  int xp;  
  const int id;
  const Data_t data;
};

哈希函数不考虑非const成员xp,所以上面的赋值对于元素在集合中的顺序应该是完全安全的。我不想删除元素并重新插入它,因为性能实际上是这里的一个问题。

我想我可以使用const-cast,但这会损害我的代码的可读性,看起来像一个讨厌的hack。我还有别的选择吗?

不允许修改QSet元素,因为修改其中一个哈希结果可能会破坏容器的内部结构。

对于标准的关联容器,在标准节§23.2.4

关联容器的

迭代器是双向迭代器类别。对于值类型相同的关联容器作为键类型,iterator和const_iterator都是常量迭代器。是否迭代器和是未指定的Const_iterator是相同的类型。

如果您知道您的修改对排序位置元素没有影响,则使用const_cast是少数可以使用的情况之一。

然而,惯用的方法是使用提示插入:
  1. 找到要修改的元素
  2. 复制元素
  3. 修改副本
  4. 删除元素
  5. 插入副本,在可用时使用提示插入(QSet没有)

例子:

  s.erase(original);
  // modify p ...
  s.insert(copy, hint);

指出:

  1. 同样适用于其他关联容器。
  2. 这个问题在Scott Meyers的"Effective STL, Item 22"中有广泛的讨论。
  3. 有时考虑std::vector作为std::set的替代品是一个好主意

set的元素不能重复。如果允许更改元素,那么就不需要维护所有这些逻辑。因此,您需要擦除现有元素并插入新元素。

所以除非你使用const_cast,否则没有其他方法可以做到这一点。然而,如前所述,这样做可能会破坏set,允许它具有潜在的重复值。

这是如何做一个std::set<int>(我知道它不是一个QT集,但逻辑应该是相同的):

std::set<int> mySet;
mySet.insert(3);
mySet.insert(4);
for (auto i = mySet.begin(); i != mySet.end(); i++)
{
    int* elem = const_cast<int*>(&*i);
    *elem = 6;
}