C + + STL集更新是乏味的:我不能改变一个元素

由于在cppreference上没有这样的API,所以我发现更新操作很麻烦 。 所以我现在做的是这样的:

//find element in set by iterator Element copy = *iterator; ... // update member value on copy, varies Set.erase(iterator); Set.insert(copy); 

基本上由Set返回的迭代器是一个const_iterator,你不能直接改变它的值。

有没有更好的方法来做到这一点? 或者,也许我应该重写创build自己的(我不知道它是如何工作的)

set返回const_iterators (标准说set<T>::iteratorconst ,而set<T>::const_iteratorset<T>::iterator实际上可以是相同的types – 参见n3000中的23.2.4 / 6 .pdf),因为它是一个有序的容器。 如果它返回一个常规的iterator ,你可以从容器下面改变项目的值,这可能会改变顺序。

你的解决scheme是改变set项目的惯用方法。

有两种方法可以做到这一点:

  • 您可以对不属于该键的variables使用mutable
  • 你可以将你的类分成一个Key Value对(并使用std::map

现在,问题是棘手的情况:当更新实际上修改对象的key部分时会发生什么? 你的方法是有效的,尽pipe我承认这很乏味。

更新:尽pipe到目前为止,以下情况是正确的,但是这种行为被认为是一种缺陷 ,并将在即将到来的标准版本中进行更改。 真伤心


有几点让你的问题相当混乱。

  1. 函数可以返回值,类不能。 std::set是一个类,因此不能返回任何东西。
  2. 如果你可以调用s.erase(iter) ,那么它不是一个const_iteratorerase需要一个非const的迭代器。
  3. 只要set非const, std::set所有返回迭代器的成员函数都会返回一个非const迭代器。

只要更新不会改变元素的顺序,您就可以更改一个元素的值。 下面的代码编译和工作就好了。

 #include <set> int main() { std::set<int> s; s.insert(10); s.insert(20); std::set<int>::iterator iter = s.find(20); // OK *iter = 30; // error, the following changes the order of elements // *iter = 0; } 

如果您的更新更改元素的顺序,则必须擦除并重新插入。

你可能想要使用一个std :: map来代替。 使用影响sorting键的Element部分,并将所有Element作为值。 会有一些小的数据重复,但你会有更容易(可能更快)的更新。

我在C ++ 11中遇到了同样的问题,其中::std::set<T>::iterator是常量,因此不允许改变它的内容,即使我们知道这个变换不会影响< invariant 。 你可以通过将::std::set包装成mutable_settypes来解决这个问题,或者为内容写一个包装:

  template <typename T> struct MutableWrapper { mutable T data; MutableWrapper(T const& data) : data(data) {} MutableWrapper(T&& data) : data(data) {} MutableWrapper const& operator=(T const& data) { this->data = data; } operator T&() const { return data; } T* operator->() const { return &data; } friend bool operator<(MutableWrapper const& a, MutableWrapper const& b) { return a.data < b.data; } friend bool operator==(MutableWrapper const& a, MutableWrapper const& b) { return a.data == b.data; } friend bool operator!=(MutableWrapper const& a, MutableWrapper const& b) { return a.data != b.data; } }; 

我觉得这更简单,它在90%的情况下工作,没有用户甚至没有注意到在集合和实际types之间的东西。

如果你的集合包含你想改变的对象,确保你把它们的指针存储在集合中。

那么这并不妨碍你插入多个对象具有相同的值(以及你不能插入多个相同的对象),但它有用的,如果你想快速插入和删除容器。

在某些情况下这是更快的:

 std::pair<std::set<int>::iterator, bool> result = Set.insert(value); if (!result.second) { Set.erase(result.first); Set.insert(value); } 

如果该值通常不在std :: set中,那么这可以有更好的性能。