2015-06-06 5 views
3

Проблема:Как условно удалить элемент из списка с помощью итератора?

Я пишу простое приложение для файлового менеджера. В этой программе у меня есть «Directory» класс:

class Directory 
{ 
public: 
    Directory(string address, string directoryname) 
    { 
     this->path = address; 
     this->name = directoryname; 
    } 
    string GetFullPath(){ return path == "/" ? path + name : path + "/" + name; } 
    string path; 
    string name; 
    string user; 
}; 

и связанный список объектов каталога:

list<Directory*> DirectoryList; 

Я хочу, чтобы реализовать команду "rm -r directorypath" оболочки в Linux, так что мне нужно, чтобы просмотреть через список и удалить каталог «directorypath» и все его подкаталоги. Проблема в том, что я не знаю, как просмотреть список ссылок и удалить все каталоги, родительский каталог которых - «путь к каталогу». Я пробовал эти два метода:

метод 1:

Этот метод встречает ошибку во время выполнения, поскольку он не может получить доступ к списку больше после первого удаления.

for (auto address : DirectoryList) 
     if (address->GetFullPath() == directorypath) 
     { 
      for (auto subdirectory : DirectoryList) 
      if (subdirectory ->path == address->GetFullPath()) 
       DirectoryList.remove(subdirectory); 
     } 

Метод 2:

for (auto address : DirectoryList) 
     if (address->GetFullPath() == directorypath) 
     { 
      for (auto it = DirectoryList.begin(); it != DirectoryList.end();) 
       it = DirectoryList.erase(it); 
      return true; 
     } 

этот метод может получить доступ ко всем элементам в совершенстве даже после удаления, но я не знаю, как проверить это, если условие с помощью итератора it:

if (subdirectory ->path == address->GetFullPath()) 
+1

Вы можете получить доступ к объекту, на который указывает итератор, с помощью '* it', т. Е. Он ведет себя как указатель. – niceguy

+1

Прочитайте в [Erase-Remove Idiom] (http://en.wikipedia.org/wiki/Erase%E2%80%93remove_idiom) для безопасного и чистого подхода. – user4581301

ответ

1

Ваш метод 1 не работает, потому что std::list.remove(val) удалить es все элементы в вашем списке, которые сравниваются с val. Вы называете это один раз, и все готово. Цикл for() не должен быть там, это не так, как он предназначен для использования. Хорошим примером является here.

Обратите внимание, что этот метод изменит ваш контейнер и его размер. Вы должны быть осторожны и убедитесь, что ваши итераторы остаются в силе после вызова erase. Я чувствую, что действительно итераторы становятся недействительными, и поэтому вы получаете ошибки.

Ваш метод 2 выглядит почти нормально. Прежде всего, совет залежных niceguy, чтобы проверить состояние:

if ((*it).path == address->GetFullPath()) 

Теперь, имейте в виду, что удаление it будет обновлять итератор, чтобы указать на место после итератора вы удалены. Это считается одним из обновлений вашего итератора, it. Он будет дополнительно обновлен в цикле for, но это не то, что вам нужно (т. Е. Два обновления на итерацию означают, что вы пропускаете некоторые элементы). Вместо этого вы можете попробовать что-то вроде этого:

auto it = DirectoryList.begin() 
while (it != DirectoryList.end()) 
{ 
    if ((*it).path == address->GetFullPath()) 
     DirectoryList.erase(it); 
} 
+1

@KamranKia Ответил ли это на ваш вопрос? –