2010-01-11 6 views
5

Ich habe vor kurzem begonnen, Boost Lambda zu verwenden und dachte, ich würde versuchen, es an Orten zu verwenden, wo es Dinge leichter lesbar machen soll.Wie Boost Lambda zu verwenden, um einen Vektor von Zeigern mit neuen Objekten zu bevölkern

Ich habe einige Code ähnlich dem folgenden

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

und später, um es zu löschen ...

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

Welche aufräumt ordentlich.

Aber ich dachte, dass ich mal ran würde bei „Lambda-ising“ die Bevölkerung des Vektors Lambda mit ... Das ist dann das Feuerwerk begann ...

Ich versuchte ..

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

, aber das warf alle Arten von Compiler-Fehlern.

Alle Ideen, die der beste "Lambda" Weg ist, dies zu erreichen.

Thx Mark.

+0

Im Allgemeinen nicht dynamisch zugewiesene Zeiger in einem Vektor speichern - Ihr Code ist nicht ausnahmesicher und wird Speicher verlieren, wenn ein Konstruktor von X fehlschlägt. –

+0

Hallo Joe, ich wäre daran interessiert, dies zu erweitern. Ich bin nicht sicher, wie der Konstruktor von X fehlschlagen und Speicher verlieren könnte. Ich dachte, dass der C++ - Standard sagte, dass angesichts von Ausnahmen neu null zurückgegeben wird und den Speicher aufräumt, bevor die Ausnahme erneut ausgelöst wird. Natürlich könnte ich völlig falsch liegen. – ScaryAardvark

+0

@ScaryAardvark. Neue Würfe std :: bad_alloc, wenn der Speicher nicht ausreicht - es gibt niemals null zurück, es sei denn, Sie verwenden das nicht-werfen-Formular. –

Antwort

9

Hier ist ein Code-Snippet, das tut, was Sie wollen:

#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()); 
} 

Vielleicht möchten Sie allerdings mit boost :: ptr_vector prüfen, wie ein std :: vector mit dynamisch zugewiesenen Zeiger in einer Ausnahme sicheren Weg isn mit nicht leicht.

+0

Wenn Sie das erreichen wollten, könnten Sie einfach einen v.reserve (20) vor dem Aufruf generate_n anlegen. –

0

Kann Ihnen nicht mit Lambda helfen, aber haben Sie sich boost::assign Bibliothek angesehen?

+0

Nein, aber ich werde es gleich überprüfen. – ScaryAardvark

0

Ok, Nach einem Extra an Spiel kam ich mit diesem nach oben ...

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

Ich bin nicht ganz sicher, dass dies so elegant ist. Aus einer Programmierperspektive kann es sein, aber von einer "In-6-Monate-Zeit-werde-ich-weiß-was-das-schon-zu-tun-Perspektive" bin ich mir nicht sicher ...

Fühlen Sie sich frei, bessere Möglichkeiten, dies zu tun.

+0

Mindestens std :: back_inserter (v) macht es ein wenig lesbarer. – stefaanv

+0

std :: back_insertors Template-Target ist ein Typ keine Instanz, also muss es leider std :: vector < X * >, nicht v – ScaryAardvark

+0

back_inserter ist eine Funktion, so dass es automatisch das tempalte Argument ableiten kann - siehe meine Antwort unten. –

4

Sie sollten erwägen:

static const int PtrVectorSize = 20; 

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

Auch Sie boost::ptr_vector verwenden könnte und Sie sich selbst die Löschungen speichern.

+0

Ja, das ist sicherlich leserlicher. Ich mag die Art, wie Sie den back_inserter durch Größenanpassung loswerden .. – ScaryAardvark

+0

Es ist sehr wahrscheinlich ein wenig effizienter, eine Reserve oder eine Größenänderung vor dem Füllen des Generators zu machen, und ich bevorzuge normalerweise die Resize/Iterator über die Reserve/back_inserter für Sequenzen einer bekannten Größe, obwohl ich denke, dass der zweite in einem außergewöhnlichen Sinn als "sicherer" betrachtet werden könnte. –