这是我的代码:
while (it!=s.end()) //here 's' is a set of stl and 'it' is iterator of set
{
*it=*it-sub; //'sub' is an int value
it++;
}
Run Code Online (Sandbox Code Playgroud)
我无法更新迭代器设置的值。我想从集合的所有元素中减去一个整数值“sub”。
任何人都可以帮助我真正的问题在哪里以及实际的解决方案是什么?
这是错误消息:
error: assignment of read-only location ‘it.std::_Rb_tree_const_iterator<int>::operator*()’
28 | *it=*it-sub;
| ~~~^~~~~~~~
Run Code Online (Sandbox Code Playgroud)
Sch*_*eff 22
astd::set中元素的键值是const有充分理由的。修改它们可能会破坏对std::set.
因此,解决方案是擦除迭代器并插入一个带有 key 的新迭代器*it - sub。请注意,std::set::erase()返回一个新的迭代器,必须在您的情况下使用它来保持 while 循环正常工作。
#include<iostream>
#include<set>
template <typename T>
std::ostream& operator<<(std::ostream &out, const std::set<T> &values)
{
const char *sep = "{ ";
for (const T &value : values) { out << sep << value; sep = ", "; }
return out << " }";
}
int main()
{
std::set<int> test{ 11, 12, 13, 14, 15 };
std::cout << "test: " << test << '\n';
const int sub = 10;
std::set<int>::iterator iter = test.begin();
while (iter != test.end()) {
const int value = *iter;
iter = test.erase(iter);
test.insert(value - sub);
}
std::cout << "test: " << test << '\n';
}
Run Code Online (Sandbox Code Playgroud)
输出:
#include<iostream>
#include<set>
template <typename T>
std::ostream& operator<<(std::ostream &out, const std::set<T> &values)
{
const char *sep = "{ ";
for (const T &value : values) { out << sep << value; sep = ", "; }
return out << " }";
}
int main()
{
std::set<int> test{ 11, 12, 13, 14, 15 };
std::cout << "test: " << test << '\n';
const int sub = 10;
std::set<int>::iterator iter = test.begin();
while (iter != test.end()) {
const int value = *iter;
iter = test.erase(iter);
test.insert(value - sub);
}
std::cout << "test: " << test << '\n';
}
Run Code Online (Sandbox Code Playgroud)
std::set迭代时的更改通常不是问题,但可能会导致微妙的问题。
最重要的事实是,所有使用过的迭代器都必须保持完整,否则可能不再使用。(这就是为什么擦除元素的当前迭代器被分配了返回值,std::set::erase()它的返回值要么是一个完整的迭代器,要么是集合的结尾。)
当然,元素也可以插入到当前迭代器的后面。虽然这不是问题,但std::set它可能会打破我上面例子的循环。
为了演示它,我稍微更改了上面的示例。请注意,我添加了一个额外的计数器来授予循环终止:
#include<iostream>
#include<set>
template <typename T>
std::ostream& operator<<(std::ostream &out, const std::set<T> &values)
{
const char *sep = "{ ";
for (const T &value : values) { out << sep << value; sep = ", "; }
return out << " }";
}
int main()
{
std::set<int> test{ 11, 12, 13, 14, 15 };
std::cout << "test: " << test << '\n';
const int add = 10;
std::set<int>::iterator iter = test.begin();
int n = 7;
while (iter != test.end()) {
if (n-- > 0) {
const int value = *iter;
iter = test.erase(iter);
test.insert(value + add);
} else ++iter;
}
std::cout << "test: " << test << '\n';
}
Run Code Online (Sandbox Code Playgroud)
输出:
test: { 11, 12, 13, 14, 15 }
test: { 1, 2, 3, 4, 5 }
Run Code Online (Sandbox Code Playgroud)
很简单,只需用另一套替换它
std::set<int> copy;
for (auto i : s)
copy.insert(i - sub);
s.swap(copy);
Run Code Online (Sandbox Code Playgroud)
你不能std::set按设计改变元素。看
https://en.cppreference.com/w/cpp/container/set/begin
因为 iterator 和 const_iterator 都是常量迭代器(并且实际上可能是相同的类型),所以不可能通过这些成员函数中的任何一个返回的迭代器来改变容器的元素。
那是因为 set 是sorted。如果您在已排序的集合中改变元素,则必须再次对集合进行排序,这当然是可能的,但不是 C++ 方式。
您的选择是:
std::set,修改它,然后再次插入。(如果你想修改每个元素不是一个好主意)