我有两套,我正在尝试做一个联合(我在做交叉时得到同样的错误)。这是错误:
error C3892: 'std::_Tree_const_iterator<_Mytree>::operator *' : you cannot assign to a variable that is const
代码片段(如果我用 - &gt;注释掉该行,那么代码编译并且我的工作方式可以正常工作):
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++;
}
我确信这是愚蠢的,但我有点迷茫。我认为代码片段应该足够了,但我可以提供其他所需的东西。感谢。
答案 0 :(得分:6)
这是C ++,而不是Java [edit:或.NET]。你几乎肯定想要替换(例如):
set<Line *> * newSet = new set<Line *>();
只是:
set<Line *> newSet;
...或者,更好的是,可能只是:
set<Line> newSet;
虽然根据您发布的代码确定无法确定,但您的left
和right
也不应该在指针中处理 - 如果他们'要做任何类似的事情,参考可能更有意义(但是,正如我所说,基于你发布的内容,不可能肯定地说)。
一旦你完成了这个,就会遇到一个小问题:set
(或multiset
,map
或multimap
)上的“正常”迭代器是真的是一个const_iterator。一旦将某些内容插入到关联容器中,就不允许更改它,因为这可能会破坏集合的不变量(被排序)。如果要更改现有项,则需要从包含中删除if,进行更改,然后将更改的对象插回容器中。在您的情况下,您只是插入新项目,因此您需要insert_iterator
。
由于您不打算修改left
或right
,因此您也可以将其视为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::copy
和std::ostream_iterator
的组合,这就是你可能想要在现实中处理这个问题的方法:
std::copy(newSet.begin(), newSet.end(),
std::ostream_iterator<Line>(std::cout, "\n"));
但请注意,就标准库而言,ostream_iterator
只是另一个迭代器。如果您打算打印出left
和right
的联合,您甚至可以跳过创建一个集合以保存该联合,并直接将其打印出来:
std::set_union(left.cbegin(), left.cend(),
right.cbegin(), right.cend(),
std::ostream_iterator<Line>(std::cout, "\n"));
ostream_iterator
写入文件而不是将内容放入正常集合这一事实与标准库完全无关。它有几类迭代器,可以将输出写入任何迭代器,模拟正确的类。
现在,我可能会开枪,可能会说 - 在将数据写入控制台之前,可能需要对数据进行其他处理。我的观点并不是你必须直接将联合写入标准输出,而只是在打印出来之前你不必将其写入其他集合。
答案 1 :(得分:2)
set迭代器不是输出迭代器。使用此:
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++;
}