используя функцию стирания в std::vector

У меня есть эта функция, ее цель - удалить указатель класса BaseFile из вектора, называемого дочерними элементами

 //children is vector of type vector<BaseFile*>
void Directory::removeFile(BaseFile* file)
{
   for(int i = 0 ; (unsigned)i < children.size() ; i++)
    {
        if ((children[i]->getName()).compare(file->getName()) == 0)
        {    
            BaseFile* a = children[i];
            children.erase(children.begin()+i);
            if(a != nullptr) 
            {
                delete a;//err in this line : double free or corruption
            }
        } 
    }
}

первый вопрос: почему я получаю сообщение об ошибке в строке (удалить a;)? доза метода Erase удаляет указатель и удаляет его? если да, как я могу удалить указатель из вектора, не удаляя его содержимое в куче/стеке?


person Baraa Natour    schedule 14.11.2017    source источник
comment
этот код ошибочен, если вы хотите стереть более одного элемента за одну итерацию. в остальном просто прочитайте документы   -  person Serve Laurijssen    schedule 14.11.2017
comment
Я не уверен, что понял, что ты попросил меня сделать!!!   -  person Baraa Natour    schedule 14.11.2017
comment
Они попросили вас прочитать документацию   -  person StoryTeller - Unslander Monica    schedule 14.11.2017
comment
Я уже сделал... документация не сильно помогла; все примеры в документации относятся к целым числам. Я спрашиваю в случае, когда у меня есть указатели, хранящиеся в vecor, при стирании их с помощью стирания нужно ли удалять? если да, то почему я получаю ошибку в строке (удалить a;), если нет, как я могу удалить указатель из вектора, не удаляя его, пожалуйста, попробуйте помочь.   -  person Baraa Natour    schedule 14.11.2017
comment
Я думаю, что ошибка не в показанном коде, но, как уже сказал Лаурийссен, он ошибочен. Вы, например, дважды добавляли один и тот же BaseFile к вектору?   -  person alain    schedule 14.11.2017
comment
нет, пока я написал несколько функций и тестирую их, удаление BaseFile* — единственное   -  person Baraa Natour    schedule 14.11.2017
comment
Я думаю, вы также можете использовать std::remove_if для этой задачи.   -  person HMD    schedule 14.11.2017
comment
Вы использовали new для создания BaseFile?   -  person    schedule 14.11.2017
comment
в конце концов я понял, что пытался удалить объект из стека, это немного глупо, но все же публикация моего вопроса здесь мне очень помогла :)   -  person Baraa Natour    schedule 14.11.2017


Ответы (1)


Что вам нужно сделать, так это использовать std::remove_if для получения вектора без соответствующего элемента.

Однако после того, как вы выполнили вызов std::remove_if, у вас не будет возможности delete совпадающих элементов в качестве документация гласит (выделено мной):

Удаление выполняется путем сдвига (посредством присваивания перемещения) элементов в диапазоне таким образом, чтобы элементы, которые не подлежат удалению, оказались в начале диапазона. Относительный порядок оставшихся элементов сохраняется, а физический размер контейнера не изменяется. Итераторы, указывающие на элемент между новым логическим концом и физическим концом диапазона, по-прежнему могут быть разыменованы, но сами элементы имеют неуказанные значения (согласно постусловию MoveAssignable).

Поэтому мы будем обрабатывать удаление непосредственно в предикате. Обратите внимание, что мы также должны позаботиться о том, чтобы ничего не освободить дважды, поэтому мы будем отслеживать удаленный элемент с помощью std::unordered_set

void Directory::removeFile(BaseFile *file) {
     std::unordered_set<BaseFile*> deleted_set { file }; // Just to avoid deleting the input argument if it's stored in children as well...
     auto match_it = std::remove_if(begin(children), end(children),
          [&](BaseFile *current_file) -> bool {
              bool result = current_file->getName().compare(file->getName()) == 0;
              if (result && end(deleted_set) == deleted_set.find(current_file)) {
                  delete current_file;
                  deleted_set.insert(current_file);
              }
              return result;
          });
     children.erase(match_it, end(children));
}

Наконец, я надеюсь, что указатель, который вы указываете в качестве аргумента file, также не является членом children, и если это так, то вы не закончите тем, что delete используете его!

Примечание. Можно ли использовать интеллектуальные указатели в вашем случае? Кажется, что объект Directory владеет объектами BaseFile, хранящимися в children... Так что, возможно, std::unique_ptr поможет...

person Rerito    schedule 14.11.2017
comment
у меня осталось несколько вопросов в цикле for, почему я должен использовать [for(....; ++it)], а не [for(....; it++)] и второй вопрос: - в вашем коде( за что я благодарю вас за это) (* это) указатель на конец моего нового вектора, это элемент, который я не хочу удалять, не так ли (это = match_it +1) - person Baraa Natour; 14.11.2017
comment
@BaraaNatour ++it или it++ на самом деле не имеет значения, хотя вы можете заметить улучшение производительности при использовании первого (см. stackoverflow.com/a/38948073/ 1794345) - person Rerito; 14.11.2017
comment
@BaraaNatour Я только что заметил, что вы не можете удалить элемент после использования remove_if в соответствии с его документацией. Дайте мне немного времени, чтобы исправить мой ответ и пролить свет на ваши опасения. - person Rerito; 14.11.2017