2010-01-11 11 views
5

Recientemente comencé a usar boost lambda y pensé que lo intentaría y lo usaría en lugares donde debería/debería facilitar la lectura.Cómo usar boost lambda para rellenar un vector de punteros con objetos nuevos

que tienen algo de código similar al siguiente

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

y más tarde, para borrarlo ...

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

Qué ordena limpiamente hacia arriba.

Sin embargo, yo pensé que tendría un ir en "lambda-ising" la población del vector lambda utilizando ... Eso es entonces comenzaron los fuegos artificiales ...

Probé ..

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

pero esto arrojó todo tipo de errores de compilación.

Cualquier idea que es la mejor forma "lambda" de lograr esto.

Thx Marca.

+0

Generalmente, no almacene los punteros dinámicamente asignados en un vector: su código no es una excepción segura y perderá memoria si falla un constructor de X. –

+0

Hola Joe, me interesaría expandirme en esto. No estoy seguro de cómo el constructor de X podría fallar y perder memoria. Pensé que el estándar de C++ decía que, a pesar de las excepciones, volvería a anular y limpiar la memoria antes de volver a lanzar la excepción. Por supuesto que podría estar completamente equivocado. – ScaryAardvark

+0

@ScaryAardvark. New throws std :: bad_alloc si está fuera de memoria - nunca devuelve nulo a menos que use el formulario que no arroja. –

Respuesta

9

He aquí un fragmento de código que hace lo que quiere:

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

Es posible que desee considerar el uso de impulso :: ptr_vector sin embargo, como el uso de un std :: vector con punteros asignados dinámicamente de forma segura ISN excepción fácil.

+0

Si quiere lograr eso, puede simplemente colocar una v.reserve (20) delante de la llamada a generate_n. –

0

No puedo ayudarte con lambda, pero ¿has mirado en la biblioteca boost::assign?

+0

No, pero lo revisaré ahora mismo. – ScaryAardvark

0

Ok, después de un poco más de juego que se me ocurrió esto ...

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

No estoy muy seguro de que esto es tan elegante. Desde una perspectiva de programación, puede ser, pero desde la perspectiva de "en 6 meses de tiempo sabré qué fue lo que quería hacer", no estoy seguro ...

No dudes en señalar mejores formas de hacerlo.

+0

Al menos std :: back_inserter (v) lo hace un poco más legible. – stefaanv

+0

std :: la plantilla de destino de Back_inserter es un tipo, no una instancia, así que desafortunadamente tiene que ser std :: vector < X * >, no v – ScaryAardvark

+0

back_inserter es una función por lo que puede deducir automáticamente el argumento de tempalte - ver mi respuesta a continuación. –

4

Usted podría considerar:

static const int PtrVectorSize = 20; 

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

Además, se puede usar boost::ptr_vector y guardar su auto las eliminaciones.

+0

Sí, eso es ciertamente más legible. Me gusta la forma en que eliminaste el back_inserter cambiando el tamaño. – ScaryAardvark

+0

Es muy probable que sea un poco más eficiente hacer una reserva o un cambio de tamaño antes de llenar el generador, y normalmente estoy a favor del tamaño/iterador sobre la reserva/back_inserter para secuencias de un tamaño conocido, aunque supongo que el segundo podría considerarse "más seguro" en un sentido excepcional. –

Cuestiones relacionadas