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>::iterator
是const
,而set<T>::const_iterator
和set<T>::iterator
实际上可以是相同的types – 参见n3000中的23.2.4 / 6 .pdf),因为它是一个有序的容器。 如果它返回一个常规的iterator
,你可以从容器下面改变项目的值,这可能会改变顺序。
你的解决scheme是改变set
项目的惯用方法。
有两种方法可以做到这一点:
- 您可以对不属于该键的variables使用
mutable
- 你可以将你的类分成一个
Key
Value
对(并使用std::map
)
现在,问题是棘手的情况:当更新实际上修改对象的key
部分时会发生什么? 你的方法是有效的,尽pipe我承认这很乏味。
更新:尽pipe到目前为止,以下情况是正确的,但是这种行为被认为是一种缺陷 ,并将在即将到来的标准版本中进行更改。 真伤心
有几点让你的问题相当混乱。
- 函数可以返回值,类不能。
std::set
是一个类,因此不能返回任何东西。 - 如果你可以调用
s.erase(iter)
,那么它不是一个const_iterator
。erase
需要一个非const的迭代器。 - 只要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_set
types来解决这个问题,或者为内容写一个包装:
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中,那么这可以有更好的性能。