使用set_union和set_intersection时出错

Pet*_*ete 1 c++ intersection set

我有两套,我正在尝试做一个联合(我在做交叉时得到同样的错误).这是错误:

error C3892: 'std::_Tree_const_iterator<_Mytree>::operator *' : you cannot assign to a variable that is const
Run Code Online (Sandbox Code Playgroud)

代码片段(如果我用 - >注释掉行,那么代码编译并且我的工作方式可以正常工作):

    set<Line *>::iterator it;
    set<Line *> * newSet = new set<Line *>();
    leftLines = pLeft->getSet();
    rightLines = pRight->getSet();
 -->it = set_union(leftLines->begin(),leftLines->end(),rightLines->begin(), rightLines->end(), newSet->begin());
    for(it = leftLines->begin(); it != leftLines->end(); it++)
    {
        newSet->insert(*it);
    }
    for(it = rightLines->begin(); it != rightLines->end(); it++)
    {
        newSet->insert(*it);
    }
    it = newSet->begin();
    while(it != newSet->end())
    {
        result->insert(*it);
        it++;
    }
Run Code Online (Sandbox Code Playgroud)

我确定这是愚蠢的但我有点迷茫.我认为代码片段应该足够了,但我可以提供其他所需的东西.谢谢.

Jer*_*fin 6

这是C++,而不是Java [edit:或.NET].你几乎肯定想要替换(例如):

set<Line *> * newSet = new set<Line *>();
Run Code Online (Sandbox Code Playgroud)

只是:

set<Line *> newSet;
Run Code Online (Sandbox Code Playgroud)

...或者,更好的是,可能只是:

set<Line> newSet;
Run Code Online (Sandbox Code Playgroud)

虽然基于你发布的代码是不可能肯定地说的,但是你的left并且right不应该处理指针是非常公平的- 如果他们要做任何类似的事情,参考可能会使更有意义(尽管如我所说,基于你发布的内容,我们无法肯定地说).

一旦你完成了这个,你会遇到一个小问题:一个set(或multiset,mapmultimap)的"正常"迭代器实际上是一个const_iterator.一旦将某些内容插入到关联容器中,就不允许更改它,因为这可能会破坏集合的不变量(被排序).如果要更改现有项,则需要从包含中删除if,进行更改,然后将更改的对象插回容器中.在你的情况下,你只是插入新项目,所以你想要一个insert_iterator.

既然你不打算修改或者left还是right,你还不如把他们当作const还有:

std::set_union(left.cbegin(), left.cend(), 
               right.cbegin(), right.cend(), 
               std::inserter(newSet, newSet.end()));
Run Code Online (Sandbox Code Playgroud)

如果您决定自己模拟set_union,可以执行以下操作:

std::set<Line> newSet(left.cbegin(), left.cend());  
std::copy(right.cbegin(), right.cend(), std::inserter(newSet, newSet.end()));
Run Code Online (Sandbox Code Playgroud)

编辑:

您通常希望将迭代器传递到容器中,而不是将指针传递给容器.例如,要打印出内容,您显然现在有类似的东西:

void print_data(std::vector<Line *> const *data) { 
     for (int i=0; i<data->size(); i++)
         std::cout << *(*data)[i] << "\n";
}
Run Code Online (Sandbox Code Playgroud)

它可能有更多格式等等,但目前我们将忽略这些细节并假设它就这么简单.要直接从您选择的容器中写入数据,通常需要一个接受任意类型迭代器的模板:

template <class inIt>
void print_data(inIt begin, inIt end) { 
     while (begin != end) 
         std::cout << *begin++ << '\n';
}
Run Code Online (Sandbox Code Playgroud)

但是,我们可以更进一步,并将输出指定为迭代器:

template <class inIt, class outIt>
void print_data(inIt begin, inIt end, outIt dest) { 
    while (begin != end) {
        *dest++ = *begin++;
        *dest++ = '\n';
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以再多做一步,并允许用户指定要在项目之间使用的分隔符,而不是始终使用'\n',但此时,您只需要复制标准库中已有的内容 - - 一个std::copy和一个的组合std::ostream_iterator,这就是你可能想要在现实中处理这个问题的方法:

std::copy(newSet.begin(), newSet.end(), 
          std::ostream_iterator<Line>(std::cout, "\n"));
Run Code Online (Sandbox Code Playgroud)

但请注意,就标准库而言,a ostream_iterator只是另一个迭代器.如果您打算打印出left和的并集right,您甚至可以跳过创建一个用于保存该联合的集合,并直接将其打印出来:

std::set_union(left.cbegin(), left.cend(),
               right.cbegin(), right.cend(), 
               std::ostream_iterator<Line>(std::cout, "\n"));
Run Code Online (Sandbox Code Playgroud)

ostream_iterator写入文件而不是将内容放入普通集合这一事实与标准库完全无关.它有几类迭代器,可以将输出写入任何模拟正确类的迭代器.

现在,我可能会开枪,可能会说 - 在将数据写入控制台之前,可能需要对数据进行其他处理.我的观点并不是你必须直接将联合写入标准输出,而只是在打印之前你不一定要将它写入其他集合.