2010-01-11 9 views
5

Niedawno zacząłem używać boost lambda i sądziłem, że spróbuję użyć go w miejscach, w których powinien/powinien ułatwić czytanie.Jak używać boost lambda do wypełnienia wektora wskaźników nowymi obiektami

Mam kod podobny do poniższego

std::vector< X * > v; 
for (int i = 0 ; i < 20 ; ++i) 
    v.push_back(new X()); 

i później, aby go usunąć ...

std::for_each(v.begin(), v.end(), boost::lamda::delete_ptr()); 

Które starannie porządkuje się.

Jednak pomyślałem, że mam go na „lambda-Ising” populacji wektora za pomocą lambda ... To wtedy fajerwerki zaczęło ...

Próbowałem ..

std::generate_n(v.begin(), 20, _1 = new X()); 

ale to spowodowało wszystkie rodzaje błędów kompilatora.

Wszelkie pomysły, które są najlepszą metodą "lambda", aby to osiągnąć.

Thx Oznacz.

+0

Generalnie nie przechowuj dynamicznie przydzielonych wskaźników w wektorze - Twój kod nie jest bezpieczny w wyjątkach i spowoduje wyciek pamięci, jeśli konstruktor X ulegnie awarii. –

+0

Witaj Joe, byłbym zainteresowany rozszerzeniem tego. Nie jestem pewien, jak konstruktor X może zawieść i przeciekać pamięci. Myślałem, że standard C++ powiedział, że nowe, w obliczu wyjątków, zwróci wartość zerową i wyczyści pamięć przed ponownym wyrzuceniem wyjątku. Oczywiście mógłbym być całkowicie w błędzie. – ScaryAardvark

+0

@SararyAardvark. New rzuca std :: bad_alloc, jeśli brakuje pamięci - nigdy nie zwróci wartości null, chyba że użyjesz formularza nie rzucającego. –

Odpowiedz

9

Oto fragment kodu, który robi to, co chcesz:

#include <algorithm> 
#include <vector> 

#include <boost/lambda/lambda.hpp> 
#include <boost/lambda/construct.hpp> 

typedef int X; 

int main() { 
    std::vector<X*> v; 
    std::generate_n(std::back_inserter(v), 20, boost::lambda::new_ptr<X>()); 
    std::for_each(v.begin(), v.end(), boost::lambda::delete_ptr()); 
} 

Można rozważyć użycie boost :: ptr_vector choć, jak za pomocą std :: vector z dynamicznie alokowanych wskaźników w wyjątku bezpieczny sposób ISN łatwo.

+0

Jeśli chcesz osiągnąć to, możesz po prostu wetknąć infekcję v.reserve (20) do wywołania generate_n. –

0

Ok, Po dodatkowym bitem grania wymyśliłem ten ...

std::generate_n(std::back_insert_iterator< std::vector< X* > >(ip), 20, new_ptr<X>())); 

Nie jestem całkiem pewien, że to jest tak elegancki. Z perspektywy programistycznej może być, ale z perspektywy "w ciągu 6 miesięcy-będzie-wiem-co-ten-był-znaczony-do-zrobienia", nie jestem pewien ...

Zapraszam do wskazania lepszych sposobów robienia tego.

+0

Przynajmniej std :: back_inserter (v) czyni go bardziej czytelnym. – stefaanv

+0

std :: szablon docelowy back_inserter jest typem nie instancją, więc niestety musi to być std :: vector < X * >, a nie v – ScaryAardvark

+0

back_inserter jest funkcją, która automatycznie wyprowadza argument tempalte - zobacz moją odpowiedź poniżej. –

4

Można rozważyć:

static const int PtrVectorSize = 20; 

// .... 
v.resize(PtrVectorSize); 
generate_n(v.begin(), PtrVectorSize, new_ptr<X>()); 

Ponadto, można użyć boost::ptr_vector i zapisz samoobsługowa Usuwa.

+0

Tak, to z pewnością bardziej czytelne. Podoba mi się sposób, w jaki pozbyłeś się back_inserter poprzez zmianę rozmiaru .. – ScaryAardvark

+0

Najprawdopodobniej trochę bardziej wydajne jest zrobić rezerwę lub zmienić rozmiar przed wypełnieniem generowania, a ja zazwyczaj preferuję zmianę rozmiaru/iteratora nad rezerwą/back_inserter dla sekwencji o znanym rozmiarze, choć przypuszczam, że drugi może być uważany za "bezpieczniejszy" w wyjątkowym sensie. –

Powiązane problemy