使用 set_union 和 set_intersection 时出错

发布于 2024-11-01 17:09:22 字数 973 浏览 5 评论 0原文

我有两组,我正在尝试进行并集(在进行相交时出现相同的错误)。这是错误:

error C3892: 'std::_Tree_const_iterator<_Mytree>::operator *' : you cannot assign to a variable that is const

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

    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++;
    }

我确信这很愚蠢,但我很友善的丢失。我认为代码片段应该足够了,但我可以提供其他需要的内容。谢谢。

I have two sets and I'm trying to do a union (I get the same error when doing an intersection). Here is the error:

error C3892: 'std::_Tree_const_iterator<_Mytree>::operator *' : you cannot assign to a variable that is const

Code snippet(if I comment out the line with the --> then the code compiles and my work around way of doing the union works fine):

    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++;
    }

I'm sure this is something silly but I'm kind of lost. I think that code snippet should be enough but I can provide whatever else is needed. Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

似梦非梦 2024-11-08 17:09:22

这是 C++,而不是 Java [编辑:或 .NET]。您几乎肯定想将(例如):替换

set<Line *> * newSet = new set<Line *>();

为:

set<Line *> newSet;

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

set<Line> newSet;

虽然根据您发布的代码不可能确定,但​​您的 leftright 也不应该处理指针——如果它们要做任何类似的事情,引用可能更有意义(尽管,正如我所说,仅根据您发布的内容,无法确定)。

完成此操作后,您会遇到一个小问题:set(或multisetmapset上的“正常”迭代器code>multimap) 实际上是一个 const_iterator。一旦将某些内容插入到关联容器中,就不允许更改它,因为这可能会破坏集合的不变量(正在排序)。如果要更改现有项目,则需要从容器中删除该项目,进行更改,然后将更改后的对象插入回容器中。就您而言,您只是插入新项目,因此您需要一个 insert_iterator

由于您不打算修改 leftright,因此您也可以将它们视为 const

std::set_union(left.cbegin(), left.cend(), 
               right.cbegin(), right.cend(), 
               std::inserter(newSet, newSet.end()));

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

std::set<Line> newSet(left.cbegin(), left.cend());  
std::copy(right.cbegin(), right.cend(), std::inserter(newSet, newSet.end()));

编辑:

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

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

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

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

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

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

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

std::copy(newSet.begin(), newSet.end(), 
          std::ostream_iterator<Line>(std::cout, "\n"));

但是请注意,就标准而言库关心,ostream_iterator 只是另一个迭代器。如果您只想打印 leftright 的并集,您甚至可以跳过创建一个集合来保存该并集,而直接将其打印出来

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

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

现在,可以这么说,我可能有点操之过急——在将数据写入控制台之前,可能需要对数据进行其他处理。我的观点并不是说您必须将联合直接写入标准输出,而是说您不一定必须在打印之前将其写入其他集合。

This is C++, not Java [edit: or .NET]. You almost certainly want to replace (for example):

set<Line *> * newSet = new set<Line *>();

with just:

set<Line *> newSet;

...or, better still, probably just:

set<Line> newSet;

Although it's impossible to say for certain based on the code you've posted, there's a pretty fair chance that your left and right shouldn't be dealing in pointers either -- if they're going to do anything of the sort, a reference probably makes more sense (though, as I said, based on just what you've posted, it's impossible to say for sure).

Once you've done that, you run into a minor problem: a "normal" iterator over a set (or multiset, map or multimap) is really a const_iterator. Once you insert something into an associative container, you're not allowed to change it because that could destroy the collection's invariant (being sorted). If you want to change an existing item, you need to delete if from the contain, make the change, and insert the changed object back into the container. In your case, you're just inserting new items, so you want an insert_iterator.

Since you're not planning on modifying either left or right, you might as well treat them as const as well:

std::set_union(left.cbegin(), left.cend(), 
               right.cbegin(), right.cend(), 
               std::inserter(newSet, newSet.end()));

If you decide to simulate set_union on your own, you can do something like this:

std::set<Line> newSet(left.cbegin(), left.cend());  
std::copy(right.cbegin(), right.cend(), std::inserter(newSet, newSet.end()));

Edit:

Instead of passing around pointers to containers, you normally want to pass around iterators into the containers. For example, to print out the contents, you apparently now have something like:

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

It probably has more formatting and such, but for the moment we'll ignore those details and assume it's this simple. To write the data directly from a container of your choice, you normally want a template that will accept iterators of an arbitrary type:

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

We can, however, go a step further than that, and specify the output as an iterator as well:

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

You could go one more step, and allow the user to specify the delimiter to be used between the items, instead of always using '\n', but at that point, you'd just be duplicating something what's already in the standard library -- a combination of std::copy and an std::ostream_iterator, which is how you probably want to deal with this in reality:

std::copy(newSet.begin(), newSet.end(), 
          std::ostream_iterator<Line>(std::cout, "\n"));

Note, however, that as far as the standard library cares, an ostream_iterator is just another iterator. If you're just going to print out the union of left and right, you can skip even creating a set to hold that union, and just print it out directly:

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

The fact that an ostream_iterator writes to a file instead of putting things into a normal collection is entirely irrelevant to the standard library. It has a few classes of iterators, and can write output to any iterator that models the correct class.

Now, I may be jumping the gun, so to speak -- maybe need to do other processing on the data before you write it to the console. My point isn't that you necessarily have to write the union directly to standard output, but just that you don't necessarily have to write it to some other collection before you print it out.

烟雨凡馨 2024-11-08 17:09:22

设置迭代器不是输出迭代器。使用这个:

set_union(leftLines->begin(),leftLines->end(),rightLines->begin(), rightLines->end(), inserter(*newSet, newSet->begin()));

另外,你为什么要填充newSet?在并集/交集之后保持原样,否则并集/交集将毫无意义。

set<Line *>::iterator it;
set<Line *> newSet; // No need to `new` this
leftLines = pLeft->getSet();
rightLines = pRight->getSet();
set_union(leftLines->begin(),leftLines->end(),rightLines->begin(), rightLines->end(), inserter(newSet, newSet.begin()));

// Assuming you really need the below code - you could likely just make an inserter directly on `result` instead of the copying.
it = newSet.begin();
while(it != newSet.end())
{
    result->insert(*it);
    it++;
}

set iterators aren't output iterators. Use this:

set_union(leftLines->begin(),leftLines->end(),rightLines->begin(), rightLines->end(), inserter(*newSet, newSet->begin()));

Also, why're you filling newSet? Leave it as is after the union/intersection or the union/intersection will be pointless.

set<Line *>::iterator it;
set<Line *> newSet; // No need to `new` this
leftLines = pLeft->getSet();
rightLines = pRight->getSet();
set_union(leftLines->begin(),leftLines->end(),rightLines->begin(), rightLines->end(), inserter(newSet, newSet.begin()));

// Assuming you really need the below code - you could likely just make an inserter directly on `result` instead of the copying.
it = newSet.begin();
while(it != newSet.end())
{
    result->insert(*it);
    it++;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文