C++ C++;std::set更新很乏味:我可以';不要在适当的位置更改元素
我发现C++ C++;std::set更新很乏味:我可以';不要在适当的位置更改元素,c++,stl,set,C++,Stl,Set,我发现std::set上的更新操作很乏味,因为在上没有这样的API。所以我现在做的是这样的: //find element in set by iterator Element copy = *iterator; ... // update member value on copy, varies Set.erase(iterator); Set.insert(copy); 基本上,Set返回的迭代器是一个常量迭代器,不能直接更改其值 有更好的方法吗?或者我应该通过创建自己的(我不知道它是如何
std::set
上的更新操作很乏味,因为在上没有这样的API。所以我现在做的是这样的:
//find element in set by iterator
Element copy = *iterator;
... // update member value on copy, varies
Set.erase(iterator);
Set.insert(copy);
基本上,Set
返回的迭代器是一个常量迭代器
,不能直接更改其值
有更好的方法吗?或者我应该通过创建自己的(我不知道它是如何工作的)来覆盖
std::set
set
返回const\u迭代器
(标准规定,set::iterator
是const
,而set::const\u iterator
和set::iterator
实际上可能是同一类型-参见n3000.pdf中的23.2.4/6)因为它是一个已排序的容器。如果它返回一个常规的迭代器
,则允许您更改容器下的items值,这可能会改变排序
您的解决方案是以惯用的方式更改
集合中的项目。您可能需要使用std::map
。使用元素中影响键排序的部分,并将所有元素
作为值。会有一些较小的数据重复,但您会更轻松(可能更快)更新。更新:尽管以下情况到目前为止都是正确的,但这种行为被认为是错误的,并将在即将发布的标准版本中进行更改。这太令人伤心了
有几点让你的问题相当混乱
函数可以返回值,类不能返回值。std::set
是一个类,因此不能返回任何内容
如果可以调用s.erase(iter)
,则iter
不是一个const\u迭代器
erase
需要一个非const迭代器
返回迭代器的std::set
的所有成员函数都返回一个非常量迭代器,只要该集合也是非常量的
只要更新不改变元素的顺序,就可以更改集合中元素的值
#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;
}
#包括
int main()
{
std::集s;
s、 插入(10);
s、 插入(20);
std::set::迭代器iter=s.find(20);
//嗯
*iter=30;
//错误,以下更改元素的顺序
//*iter=0;
}
如果更新更改了元素的顺序,则必须擦除并重新插入。在简单的情况下,有两种方法可以做到这一点:
- 您可以对不属于键的变量使用
mutable
- 您可以将类拆分为
键
值
对(并使用std::map
)
现在,问题是棘手的情况:当更新实际修改对象的键
部分时会发生什么?您的方法很有效,尽管我承认它很乏味。在某些情况下,这会更快:
std::pair<std::set<int>::iterator, bool> result = Set.insert(value);
if (!result.second) {
Set.erase(result.first);
Set.insert(value);
}
std::pair result=Set.insert(值);
如果(!result.second){
设置。擦除(结果。第一);
设置。插入(值);
}
如果值通常不在std::set
中,那么这可能会有更好的性能。我在C++11中遇到了同样的问题,在C++11中,::std::set::iterator
确实是常量,因此不允许更改其内容,即使我们知道转换不会影响
data=data;}
运算符T&()常量{返回数据;}
T*运算符->()常量{return&data;}
friend bool运算符在C++17中,由于以下原因,您可以使用它做得更好:
这将避免额外的类型副本和额外的分配/解除分配,并且也适用于仅移动类型
您还可以按键提取。如果缺少键,这将返回一个空节点:
auto node = Set.extract(key);
if (node) // alternatively, !node.empty()
{
node.value() = 42;
Set.insert(std::move(node));
}
如果你发现使用2条语句已经很乏味,那么就创建一个内联函数。KennyTM一针见血。这样做没有任何性能方面的负面影响,所以现在就做吧!:-PIf如果你编写一个更新函数,你可能会想用与Boost相同的方式对其建模。MultiIndex:cplusplus.com是一个糟糕的参考。查找语言的方面“冗长”是因为它看起来…奇怪。我认为这种方法的缺点是在并发处理的情况下使用读/写锁。(非常量)std::set
的成员不返回const\u迭代器
,如果你小心的话,你可以修改它的元素。为什么(不正确)答案得到这么多的支持票?我遗漏了什么?我的答案是正确的-你的答案是错误的。我更新了我的帖子,引用了标准。Terry,谢谢你的讨论。我重新检查了一下:缺陷报告确实是在1998年提交的,但没有被纳入C++03。它将被纳入C++0x。因此,尽管你的答案到目前为止并不正确就目前的标准而言,就其意图而言,它是正确的。+1.感谢您的评论以及您与Avakar(或Avatar?)的辩论。他们帮助了很多。@Avakar:元素在技术上是可变的,但不允许更改。这是标准中的一个缺陷。好吧,我在看23.1.2[lib.associative.reqmts]关于C++03,表69,上面写着:“a.find(k):迭代器;常量a的常量迭代器”。我手头没有C++03 pdf(它需要钱)。我认为这在C++03中是固定的,但它可能是03后的修复。在n3000.pdf中,它是23.2.4/6,这解释了对于关联容器,迭代器是常量迭代器(可以是与const_迭代器相同的类型)。您使用的编译器是什么?此行为是imp
// remove element from the set, but without needing
// to copy it or deallocate it
auto node = Set.extract(iterator);
// make changes to the value in place
node.value() = 42;
// reinsert it into the set, but again without needing
// to copy or allocate
Set.insert(std::move(node));
auto node = Set.extract(key);
if (node) // alternatively, !node.empty()
{
node.value() = 42;
Set.insert(std::move(node));
}