Czyszczenie listy STL / wektora wskaźników

Jaki jest najkrótszy fragment C++, jaki można wymyślić, aby bezpiecznie wyczyścić wektor lub listę wskaźników? (zakładając, że musisz wywołać delete na wskaźnikach?)

list<Foo*> foo_list;

Wolałbym nie używać Boost lub owinąć moje wskaźniki Z Inteligentnych wskaźników.

 49
Author: twk, 2008-11-21

15 answers

Ponieważ rzucamy rękawicę tutaj... "Najkrótszy fragment C++"

static bool deleteAll( Foo * theElement ) { delete theElement; return true; }

foo_list . remove_if ( deleteAll );
Myślę, że możemy zaufać ludziom, którzy wymyślili STL, że mają skuteczne algorytmy. Po co odkrywać koło na nowo?
 53
Author: Mr.Ree,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-21 00:06:05

Dla std::list<T*> Zastosowanie:

while(!foo.empty()) delete foo.front(), foo.pop_front();

Dla std::vector<T*> Zastosowanie:

while(!bar.empty()) delete bar.back(), bar.pop_back();

Nie wiem dlaczego wziąłem front zamiast back ZA std::list powyżej. Myślę, że to uczucie, że jest szybsze. Ale w rzeczywistości oba są stałym czasem :). W każdym razie zawiń go w funkcję i baw się dobrze:

template<typename Container>
void delete_them(Container& c) { while(!c.empty()) delete c.back(), c.pop_back(); }
 53
Author: Johannes Schaub - litb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-16 20:46:11
for(list<Foo*>::const_iterator it = foo_list.begin(); it != foo_list.end(); ++it)
{
    delete *it;
} 
foo_list.clear();
 29
Author: Douglas Leeder,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-16 14:19:38

Jeśli pozwolisz C++11, możesz zrobić bardzo krótką wersję odpowiedzi Douglasa Leedera:

for(auto &it:foo_list) delete it; foo_list.clear();
 16
Author: Adisak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-12 22:04:31

To naprawdę niebezpieczne polegać na kodzie poza kontenerem, aby usunąć swoje wskaźniki. Co się stanie, gdy kontener zostanie zniszczony na przykład w wyniku wyrzucenia wyjątku?

Wiem, że mówiłeś, że nie lubisz boost, ale proszę rozważ Boost pointer containers.

 13
Author: Mark Ransom,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-20 23:14:26
template< typename T >
struct delete_ptr : public std::unary_function<T,bool>
{
   bool operator()(T*pT) const { delete pT; return true; }
};

std::for_each(foo_list.begin(), foo_list.end(), delete_ptr<Foo>());
 8
Author: John Dibling,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-24 11:30:30

Nie jestem pewien, czy podejście functora wygrywa tutaj za zwięzłość.

for( list<Foo*>::iterator i = foo_list.begin(); i != foo_list.end(); ++i )
    delete *i;
Zazwyczaj odradzam to. Owijanie wskaźników w inteligentne wskaźniki lub używanie specjalistycznego kontenera wskaźników jest ogólnie bardziej wytrzymałe. Istnieje wiele sposobów na usunięcie pozycji z listy ( różne smaki erase, clear, zniszczenie listy, przypisanie przez iterator do listy itp. ). Możesz zagwarantować, że złapiesz ich wszystkich?
 6
Author: CB Bailey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-20 22:30:26

Poniższy hack usuwa wskaźniki, Gdy twoja lista wychodzi poza zakres używając RAII lub wywołując list:: clear ().

template <typename T>
class Deleter {
public:
  Deleter(T* pointer) : pointer_(pointer) { }
  Deleter(const Deleter& deleter) {
    Deleter* d = const_cast<Deleter*>(&deleter);
    pointer_ = d->pointer_;
    d->pointer_ = 0;
  }
  ~Deleter() { delete pointer_; }
  T* pointer_;
};

Przykład:

std::list<Deleter<Foo> > foo_list;
foo_list.push_back(new Foo());
foo_list.clear();
 5
Author: Linoliumz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-14 16:38:16

Przynajmniej w przypadku listy, iteracji i usuwania, a następnie wywołanie clear na końcu jest trochę nieefektywne, ponieważ polega na dwukrotnym przejechaniu listy, podczas gdy naprawdę musisz to zrobić tylko raz. Tutaj jest trochę lepszy sposób:

for (list<Foo*>::iterator i = foo_list.begin(), e = foo_list.end(); i != e; )
{
    list<Foo*>::iterator tmp(i++);
    delete *tmp;
    foo_list.erase(tmp);
}

To powiedziawszy, Twój kompilator może być wystarczająco inteligentny, aby loop combine the two anyway, w zależności od sposobu implementacji list:: clear.

 4
Author: Greg Rogers,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-20 23:19:01

Uważam, że biblioteka STD zapewnia bezpośrednią metodę zarządzania pamięcią w postaci klasy alokatora

Można rozszerzyć podstawową metodę alokatora deallocate (), aby automatycznie usuwać elementy dowolnego kontenera.

I / think / this is the type of thing it ' s intended for.

 4
Author: Jeremy Cowles,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-05 03:55:48
for(list<Foo*>::const_iterator it = foo_list.begin(); it != foo_list.end(); it++)
{
    delete *it;
} 
foo_list.clear();

Jest mały powód, dla którego nie chcesz tego robić - skutecznie powtarzasz listę dwa razy.

Std::list:: clear jest liniowy w złożoności; usuwa i niszczy jeden element na raz w pętli.

Biorąc pod uwagę powyższe najprostsze do odczytania rozwiązanie moim zdaniem to:

while(!foo_list.empty())
{
    delete foo_list.front();
    foo_list.pop_front();
}
 4
Author: Heero,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-10 06:32:46

Od C++11:

std::vector<Type*> v;
...
std::for_each(v.begin(), v.end(), std::default_delete<Type>());

Lub, jeśli piszesz kod szablonowy i chcesz uniknąć podania konkretnego typu:

std::for_each(v.begin(), v.end(),
    std::default_delete<std::remove_pointer<decltype(v)::value_type>::type>());

Które (od C++14) można skrócić jako:

std::for_each(v.begin(), v.end(),
    std::default_delete<std::remove_pointer_t<decltype(v)::value_type>>());
 3
Author: ostappus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-16 11:30:16
void remove(Foo* foo) { delete foo; }
....
for_each( foo_list.begin(), foo_list.end(), remove );
 1
Author: kendotwill,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-05 17:20:12
for (list<Foo*>::const_iterator i = foo_list.begin(), e = foo_list.end(); i != e; ++i)
    delete *i;
foo_list.clear();
 0
Author: Assaf Lavie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-20 22:30:30

To wydaje się najczystsze imo, ale twoja wersja c++ musi obsługiwać tego typu iterację (wierzę, że wszystko, co zawiera lub wyprzedza c++0x, zadziała):

for (Object *i : container) delete i;    
container.clear();
 0
Author: ComputerEngineer88,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-02 18:53:04