Ошибка при использовании set_union и set_intersection - PullRequest
1 голос
/ 14 апреля 2011

У меня есть два комплекта, и я пытаюсь сделать объединение (я получаю ту же ошибку при пересечении).Вот ошибка:

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

Я уверен, что это что-то глупое, но я отчасти потерян.Я думаю, что фрагмента кода должно быть достаточно, но я могу предоставить все, что нужно.Спасибо.

Ответы [ 2 ]

6 голосов
/ 14 апреля 2011

Это C ++, а не Java [edit: или .NET]. Вы почти наверняка захотите заменить (например):

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

только с:

set<Line *> newSet;

... или, что еще лучше, вероятно, просто:

set<Line> newSet;

Хотя невозможно сказать наверняка, основываясь на коде, который вы разместили, но вполне вероятно, что ваши left и right тоже не должны иметь дело с указателями - если они собираются это делать Что-нибудь в этом роде, ссылка, вероятно, имеет больше смысла (хотя, как я уже сказал, основываясь только на том, что вы опубликовали, невозможно сказать наверняка).

Как только вы это сделаете, вы столкнетесь с небольшой проблемой: «нормальный» итератор над set (или multiset, map или multimap) действительно является const_iterator. После того, как вы вставите что-то в ассоциативный контейнер, вам не разрешено его менять, потому что это может уничтожить инвариант коллекции (будучи отсортированным). Если вы хотите изменить существующий элемент, вам нужно удалить его из содержимого, внести изменения и вставить измененный объект обратно в контейнер. В вашем случае вы просто вставляете новые элементы, поэтому вам нужен 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 пишет в файл вместо того, чтобы помещать вещи в обычную коллекцию, совершенно не имеет отношения к стандартной библиотеке. Он имеет несколько классов итераторов и может записывать выходные данные в любой итератор, моделирующий правильный класс.

Теперь я могу прыгнуть, так сказать, - возможно, потребуется выполнить другую обработку данных, прежде чем записать их на консоль. Суть не в том, что вам обязательно нужно записывать объединение непосредственно в стандартный вывод, а просто в том, что вам не обязательно записывать его в какую-либо другую коллекцию, прежде чем распечатать.

2 голосов
/ 14 апреля 2011

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