以下代码使用std :: set“legal”?

时间:2009-05-26 20:11:41

标签: c++ stl iterator set

我有这段代码:

set<int>::iterator new_end = 
                   set_difference(set1.begin(), set1.end(),
                                  set2.begin(), set2.end(),
                                  set1.begin());
set1.erase(new_end, set1.end);

它在视觉工作室中编译并运行良好。但是,在previous question中,人们声称set的迭代器应该是const。我没有在标准中看到类似的东西。有人可以告诉我它在哪里,或者这是明确定义的行为吗?

如果不是,请提供符合我需要的代码。有没有办法在不创建临时集的情况下执行此操作?

5 个答案:

答案 0 :(得分:7)

您的代码违反了set_difference的几个不变量。来自Josuttis Book的第420页:

  • 调用者必须确保目标范围足够大或者使用插入迭代器。
  • 目标范围不应与源范围重叠。

你试图回写第一组,这是不允许的。您需要编写除源范围之外的其他位置 - 为此我们可以使用第三组:

std::set<int> set3;
std::set_difference(set1.begin(), set1.end(),
                    set2.begin(), set2.end(),
                    std::inserter(set3, set3.begin()));

std::inserter的第二个参数是关于元素应插入位置的提示。然而,这只是一个提示,请放心,这些元素最终会出现在正确的位置。 set3最初为空,因此begin()是我们可以提供的唯一提示。

在致电set_difference后,set3将包含您尝试在原始代码中包含set1的内容。如果您愿意,可以继续使用set3swap set1

<强>更新

我不确定这种情况的表现,但如果您只想删除set1中显示的set2中的所有元素,您可以尝试:

for (std::set<int>::iterator i = set2.begin(); i != set2.end(); ++i)
{
    set1.erase(*i);
}

答案 1 :(得分:5)

解决问题的一个建议:

std::set<int> tmp;
std::set_difference(set1.begin(), set1.end(),
                    set2.begin(), set2.end(),
                    std::inserter(tmp, tmp.begin()));
std::swap(tmp, set1);

如果不使用临时集(除了遍历容器并对单个元素进行擦除之外),我无法想到这样做的方法。

答案 2 :(得分:4)

不,不是。来自SGI STL Reference

  1. [first1,last1]和[result,result + n)不重叠。
  2. [first2,last2]和[result,result + n)没有 重叠。
  3. 此外,我不确定begin()是否可以用作OutputIterator,正如Nikolai N Fetissov所指出的那样。

答案 3 :(得分:1)

set_difference的第五个参数应为OutputIterator,请参阅documentation

答案 4 :(得分:1)

C ++标准没有明确规定不允许分配给set迭代器,但它确实为set_difference指定“结果范围不应与原始范围重叠”(25.3.5.3)。

到目前为止,它可能对你有用,因为你对set1和set2的内容很幸运。