2009-02-24 20 views
12

Tengo una colección de objetos polimórficos, todos derivados de mi clase Animal: Gato, Perro y Pez Monkey.¿Cuándo debería usar un vector de objetos en lugar de un vector de punteros?

Mi modo de funcionamiento habitual es almacenar estos objetos en un vector de punteros de animales, de este modo:

std :: vector < Animal *> my_vector;

 
my_vector.push_back(new Animal_Cat()); 
my_vector.push_back(new Animal_Dog()); 
my_vector.push_back(new Animal_MonkeyFish()); 

Y la vida es genial ... ¿o sí?

Recientemente me han dicho que realmente debería tratar de evitar asignar memoria de esta manera, porque hace que la gestión de la memoria sea una tarea difícil. Cuando necesito destruir mi_vector, tengo que recorrer todos los elementos y borrar todo.

No creo que pueda almacenar un vector de referencias (podría estar equivocado al respecto), así que parece que el almacenamiento de un vector de objetos animales es mi única alternativa.

¿Cuándo debo elegir utilizar un vector de punteros contra un vector de objetos? En general, ¿qué método es preferible? (Me gustaría reducir la copia de objetos tanto como sea posible.)

Respuesta

17

Debe usar un vector de objetos siempre que sea posible; but in your case it isn't possible.

Los contenedores de indicadores le permiten evitar el problema de rebanado. Pero luego tienes que llamar eliminar en cada elemento, como lo estás haciendo. Eso es molesto pero posible. Lamentablemente, hay casos (cuando se lanza una excepción) donde no puede estar seguro de que se llama correctamente a la eliminación y termina con una pérdida de memoria.

La solución principal es utilizar un puntero inteligente. Pre-C++ 11 viene con auto_ptr, but that cannot be used in a standard container. C++ 11 tiene std::unique_ptr y std::shared_ptr que están diseñados para ser usados ​​en contenedores (prefiero std::unique_ptr a menos que realmente necesite contar de referencia). Si no puede usar C++ 11, la mejor solución es Boost smart pointers.

+1

Los punteros inteligentes Boost lo convirtieron en un informe técnico, por lo que puede tener std :: tr1 :: shared_ptr <>. VC++ 9 en VS 2008 lo hace. –

+0

como referencia el C++ 0x unique_pte, que es prácticamente un reemplazo de auto_ptr, funcionará en contenedores debido a las referencias rvalue y la semántica de movimiento –

8

En este caso, almacenar un vector de Animal no funcionaría para usted, ya que sus animales tienen diferentes tamaños y no podría almacenar el objetos derivados en los espacios destinados a contener la clase base. (E incluso si son del mismo tamaño, no obtendrás el efecto polimórfico deseado, ya que se ejecutarán los métodos de la clase base; la virtualidad de un método no entrará en juego a menos que accedas a él a través de un puntero o una referencia.)

Si se quiere evitar la molestia de la gestión de la memoria usted mismo, usted podría considerar el almacenamiento de un puntero inteligente tales como shared_ptr (tenga en cuenta que auto_ptr no funciona con contenedores STL, según Max Lybbert), o alguna variante en esto. De esa forma, puedes usar tu clase polimórfica, pero es un poco menos trabajo para ti.

No existen reglas reales y rápidas sobre cuándo usar objetos y punteros, aunque vale la pena señalar que, en algunos casos, como el suyo, los objetos simplemente no funcionarán para usted. Tiendo a usar objetos cuando no hay nada que lo impida, aunque debe preocuparse por las costosas operaciones de copia como observa (aunque a veces pueden mejorarse al pasar contenedores por referencia).

+0

Huh. No sabía eso. Que desafortunado. –

+0

Nunca lo he probado, así que me pregunto, ¿por qué auto_ptr no funciona con contenedores STL? –

+0

Ah, sí. Tiene sentido. –

8

En lugar de utilizar shared_ptr con contenedores STL estándar, consulte el Boost Pointer Container Library. Está diseñado para resolver exactamente este problema.

1

Si alguna vez se oye el argumento pero será tan costosa para copiarlos estructuras todo el tiempo cuando se quiere utilizar objetos completos en lugar de punteros en un vector, entonces los 2 argumentos principales son:

  1. No tenemos que preocuparnos por los problemas de duración de los punteros, lo que significa que no hay fugas de que código particular (a menos, por supuesto, las propias estructuras tienen datos de puntero, pero esa es otra historia).
  2. La ubicación de los datos de las estructuras adyacentes en la memoria aumentará el rendimiento en escenarios de uso típicos, no disminuirá la velocidad como la indirección del puntero (en términos relativos).

El costo adicional de la copia normalmente se toma cuando se agregan cosas al contenedor, no cuando se usan datos, piense un poco al respecto: ¿qué hace más? agregar elementos o usarlos?

Sin embargo, al agregar objetos polimórficos, los punteros son necesarios para evitar el corte.

Cuestiones relacionadas