c++中的设置操作(更新现有值)

Imt*_*edi 20 c++

这是我的代码:

 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)

在coliru上进行现场演示


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)

在coliru上进行现场演示

  • 在 C++17 中,您可以“提取”节点,修改它们的键,然后将它们返回到集合中。它会更有效,因为它避免了不必要的分配。 (3认同)
  • 另一个问题是,减去的元素的值可能与“std::set”中尚未处理的值之一相同。由于您不能两次拥有相同的元素,因此插入只会使“std::set”保持不变,并且稍后您将丢失该元素。例如,考虑输入集:“{10, 20, 30}”,其中“add = 10”。 (2认同)

acr*_*075 6

很简单,只需用另一套替换它

std::set<int> copy;

for (auto i : s)
    copy.insert(i - sub);

s.swap(copy);
Run Code Online (Sandbox Code Playgroud)


x00*_*x00 5

你不能std::set按设计改变元素。看

https://en.cppreference.com/w/cpp/container/set/begin

因为 iterator 和 const_iterator 都是常量迭代器(并且实际上可能是相同的类型),所以不可能通过这些成员函数中的任何一个返回的迭代器来改变容器的元素。

那是因为 set 是sorted。如果您在已排序的集合中改变元素,则必须再次对集合进行排序,这当然是可能的,但不是 C++ 方式。

您的选择是:

  1. 使用另一种类型的集合(未排序)。
  2. 创建一个新集合并用修改后的元素填充它。
  3. 从 中删除一个元素std::set,修改它,然后再次插入。(如果你想修改每个元素不是一个好主意)