vectores una punteros programacion matriz matrices llenar ingresar funciones ejemplos datos con como codigo clase c++ pointers vector

una - C++: ¿Vector de objetos vs. vector de punteros a objetos nuevos?



punteros c++ (4)

Bueno, depende de lo que intentes hacer con tu vector.

Si no usa punteros, entonces es una copia del objeto que pasa que se pone en el vector. Si se trata de un objeto simple, y / o no desea molestarse en hacer un seguimiento del almacenamiento para ellos, esto puede ser exactamente lo que desea. Si es algo complejo o requiere mucho tiempo construirlo y destruirlo, tal vez prefiera hacer ese trabajo solo una vez cada uno y pasar los punteros al vector.

Estoy buscando mejorar mis habilidades en C ++ escribiendo un procesador de muestra de software. Toma objetos que constan de puntos en un espacio 3D y los mapea en una ventana doble y dibuja círculos de diferentes tamaños para cada punto a la vista. Cual es mejor:

class World{ vector<ObjectBaseClass> object_list; public: void generate(){ object_list.clear(); object_list.push_back(DerivedClass1()); object_list.push_back(DerivedClass2());

o...

class World{ vector<ObjectBaseClass*> object_list; public: void generate(){ object_list.clear(); object_list.push_back(new DerivedClass1()); object_list.push_back(new DerivedClass2());

?? ¿Utilizaría los punteros en el segundo ejemplo para crear nuevos objetos, derrotar el uso de vectores, porque los vectores llaman automáticamente a los destructores DerivedClass en el primer ejemplo, pero no en el segundo? ¿Los punteros a los objetos nuevos son necesarios cuando se usan vectores, ya que ellos mismos manejan la administración de la memoria siempre que use sus métodos de acceso? Ahora digamos que tengo otro método en el mundo:

void drawfrom(Viewport& view){ for (unsigned int i=0;i<object_list.size();++i){ object_list.at(i).draw(view); } }

Cuando se lo llame, se ejecutará el método de dibujo para cada objeto en la lista mundial. Digamos que quiero que las clases derivadas puedan tener sus propias versiones de draw (). ¿La lista debe ser de punteros entonces para usar el selector de método (->)?


Como explícitamente declaras que quieres mejorar tu C ++, te recomendaré que comiences a utilizar Boost . Esto puede ayudarte con tu problema de tres maneras diferentes:

Usando un shared_ptr

Usar un shared_ptr podría declarar tu vector así:

std::vector< boost::shared_ptr< ObjectBase > > object_list;

Y úsalo así:

typedef std::vector< boost::shared_ptr< ObjectBase > >::iterator ObjectIterator; for ( ObjectIterator it = object_list.begin(); it != object_list.end(); it++ ) (*it)->draw(view);

Esto le daría un polimorfismo y se usaría como si fuera un vector normal de punteros, pero el shared_ptr haría la gestión de la memoria por usted, destruyendo el objeto cuando se destruye el último shared_ptr referencia.

Nota sobre C ++ 11: en C ++ 11 shared_ptr pasó a formar parte del estándar como std::shared_ptr , por lo que ya no se requiere Boost para este enfoque. Sin embargo, a menos que realmente necesite propiedad compartida, se recomienda que use std::unique_ptr , que se introdujo recientemente en C ++ 11.

Usando un ptr_vector

Usando un ptr_vector lo harías así:

boost::ptr_vector< ObjectBase > object_list;

Y úsalo así:

typedef boost::ptr_vector< ObjectBase >::iterator ObjectIterator; for ( ObjectIterator it = object_list.begin(); it != object_list.end(); it++ ) (*it)->draw(view);

Esto nuevamente se usaría como un vector normal de punteros, pero esta vez el ptr_vector administra la vida de sus objetos. La diferencia con el primer enfoque es que aquí sus objetos se destruyen cuando el vector se destruye, mientras que arriba pueden vivir más tiempo que el contenedor, si shared_ptr otros shared_ptr s que hacen referencia a ellos.

Usando un wrapper de reference_wrapper

Utilizando un ptr_vector lo declararías así:

std::vector< boost::reference_wrapper< ObjectBase > > object_list;

Y luego úsalo así:

typedef std::vector< boost::reference_wrapper< ObjectBase > >::iterator ObjectIterator; for ( ObjectIterator it = object_list.begin(); it != object_list.end(); it++ ) it->draw(view);

Tenga en cuenta que no tiene que desreferenciar el iterador primero como en los enfoques anteriores. Sin embargo, esto solo funciona si la vida útil de los objetos se gestiona en otro lugar y se garantiza que será más larga que la del vector .

Nota sobre C ++ 11: reference_wrapper también se ha estandarizado en C ++ 11 y ahora se puede usar como std::reference_wrapper sin Boost.

Como se señaló en la respuesta de Maciej H , su primer enfoque da como resultado el corte de objetos . En general, es posible que desee examinar los iterators al usar contenedores.


En cuanto a su primera pregunta, generalmente se prefiere usar objetos asignados automáticamente en lugar de objetos asignados dinámicamente (en otras palabras, no almacenar punteros) siempre que el tipo en cuestión sea posible y no sea prohibitivamente costoso. .

Si los objetos no se pueden copiar o asignar, entonces no se pueden poner directamente en std::vector todos modos, por lo que la pregunta es discutible. Si las operaciones de copia y / o asignación son costosas (por ejemplo, el objeto almacena una gran cantidad de datos), es posible que desee almacenar punteros por razones de eficiencia. De lo contrario, generalmente es mejor no almacenar punteros exactamente por la razón que mencionaste (desasignación automática)

En cuanto a su segunda pregunta, sí, esa es otra razón válida para almacenar punteros. El despacho dinámico (llamadas a métodos virtuales) solo funciona en punteros y referencias (y no puede almacenar referencias en un std::vector ). Si necesita almacenar objetos de múltiples tipos polimórficos en el mismo vector, debe almacenar punteros para evitar rebanar.


No obtendrás lo que quieres con este código

class World{ vector<ObjectBaseClass> object_list; public: void generate(){ object_list.clear(); object_list.push_back(DerivedClass1()); object_list.push_back(DerivedClass2());

Lo que va a suceder se llama corte de objetos. Obtendrás un vector de ObjectBaseClass.

Para hacer funcionar el polimorfismo, debe usar algún tipo de punteros. Probablemente haya algunos indicadores inteligentes o referencias en boost u otras bibliotecas que se puedan utilizar y que hagan que el código sea mucho más seguro que la segunda solución propuesta.