代码之家  ›  专栏  ›  技术社区  ›  Gonzalo Solera

删除前更新元素集指针中的元素

  •  0
  • Gonzalo Solera  · 技术社区  · 6 年前

    我有一些在无序映射中分配的类实例。我也有不同的容器,用不同的顺序存储指向这些元素的指针。这意味着,例如,我有一组指向映射中分配的元素的指针,由实例字段的子集排序。

    因为我可以访问实际元素,所以我可以更改它们的字段,但我知道我不应该在集合排序中使用的字段上这样做。实际上,在更改这些字段之前,我需要做的是从集合中删除对象的指针,更改这些字段并重新插入,如下所示:

    set<Element*, Comparator> s; // Elements ordered by field_2
    
    s.erase(element);
    element->field_2 = 4;
    s.insert(element);
    

    但是,维护不同顺序的其他容器是由我自己实现的,我知道我可以更改这些值,然后通知容器字段已更新。所以我想知道我是否可以把这些指令的顺序改成这个:

    element->field_2 = 4;
    s.erase(element);
    s.insert(element);
    

    我之所以要这样做,是因为我希望所有这些容器共享相同的接口。所以理想情况下,我希望更改字段,然后调用容器的方法container.value_updated(element)。

    那么,我可以修改关键字段“2”然后立即调用“删除和插入”吗?或者删除会失败,因为字段“2”的值可能不一致?(我认为这将取决于实现,但我想确保)

    2 回复  |  直到 6 年前
        1
  •  1
  •   Scheff's Cat    6 年前

    在中用作键的数据 std::set 不能更改。否则,命令 STD::设置 STD::设置 不能再工作了。

    出于好奇,我试图用错误的方式来做。

    虽然我知道这是未定义的行为,但我运行了这个程序——这是一个很好的证明,坏事情发生了:

    #include <iostream>
    #include <set>
    #include <vector>
    
    typedef int Entry;
    
    struct Less {
      bool operator()(const Entry *p1, const Entry *p2) const
      {
        return *p1 < *p2;
      }
    };
    
    int main()
    {
      const int N = 10;
      std::vector<int> data;
      for (int i = 0; i < N; ++i) data.push_back(i);
      std::set<Entry*, Less> set;
      for (int &value : data) set.insert(&value);
      // do it wrong
      data[2] = 12;
      set.erase(&data[2]);
      set.insert(&data[2]);
      // check result
      for (const Entry *pValue : set) std::cout << ' ' << *pValue;
      std::cout << '\n';
      // done
      return 0;
    }
    

    输出:

     0 1 12 3 4 5 6 7 8 9 12
    

    Live Demo on coliru

        2
  •  1
  •   R Sahu    6 年前

    那么,我可以修改关键点吗? field_2 然后立即调用“删除并插入”?

    不。可能会破坏集合中指针的顺序。

    否则删除将失败,因为 菲尔德2 可能不一致?

    这是一个明显的可能性。然而,此时,您将看到未定义的行为。不可能预测会发生什么。

    (我认为这将取决于实现,但我想确保)

    未定义的行为部分与实现无关。