【问题标题】:What is the best way to change a set during iterations?在迭代期间更改集合的最佳方法是什么?
【发布时间】:2018-07-04 09:45:36
【问题描述】:

鉴于std::set,在时间迭代期间更改集合的最佳方法是什么?
例如:

std::set<T> s;  // T is a some type (it's not important for the question).
// insertions to s
for (std::set<T>::iterator it = s.begin(); it != s.end(); it++) {
        T saveIt(*it);
        s.erase(*it);
        s.insert( saveIt + saveIt );  // operator+ that defined at `T`
}

根据我在某些资料中读到的内容,这是不好的方式,因为:从集合中移除可能会改变集合的结构。

那么更好(/最好)的方法是什么?

【问题讨论】:

  • 您必须使用函数生成的迭代器来正确更新it。(但您也有迭代新项目的风险)
  • 一开始就地做这个有什么意义?
  • @Jarod42 现在按照你说的可以吗? (我编辑了问题)
  • 空间有限制吗?就像您提到的那样,这是一个坏主意,新的set 将是一个简单的解决方案。
  • @MaximEgorushkin:这取决于operator &lt;operator + 的实现方式。 (使用std::set&lt;int, std::greater&lt;&gt;&gt; 之类的就可以了)。

标签: c++ c++11 stdset


【解决方案1】:

您的循环可能会导致几乎无限循环,因为您不断在集合的后面添加较大的元素。直到T + T 溢出。

正确的方法是创建一个新集合:

std::set<T> s; 
std::set<T> s2; 
for(auto const& elem : s)
    s2.insert(elem + elem);
s.swap(s2);

boost::range 是单线:

#include <boost/range/adaptor/transformed.hpp>
// ...
std::set<int> s;
s = boost::copy_range<std::set<int>>(s | boost::adaptors::transformed([](int x) { return x + x; }));

【讨论】:

  • 从 C++11 开始,s = std::move(s2); 就足够了 ;-)
  • @Jarod42 它更长,但更好吗?
  • 意图更清晰,(交换是移动分配顺便说一句的有效实现)。原始数据的破坏时刻也可能不同(使用swap 延长至s2 的生命周期)。
【解决方案2】:

只需复制一份 std:set

std::set<T> s;
std::set<T> modified_s;
for (std::set<T>::iterator it = s.begin(); it != s.end(); it++) {
    modified_s.insert(*it+ *it);
}
s = std::move(modified_s);

编辑: 添加了std::move 作为对@Jodocus 的改进

【讨论】:

  • s = std::move(modified_s); 将更接近原始意图,而不是 clear
猜你喜欢
  • 2020-01-15
  • 2017-04-05
  • 1970-01-01
  • 1970-01-01
  • 2012-05-30
  • 1970-01-01
  • 2016-05-05
  • 2014-09-21
  • 1970-01-01
相关资源
最近更新 更多