Diseñando un nuevo sistema desde cero. Usaré el STL para almacenar listas y mapas de ciertos objetos de larga vida.
Pregunta: ¿Debo asegurarme de que mis objetos tengan constructores de copias y almacenar copias de objetos dentro de mis contenedores STL, o es generalmente mejor administrar la vida y el alcance yo mismo y simplemente almacenar los punteros a esos objetos en mis contenedores STL?
Me doy cuenta de que esto es algo breve en detalles, pero estoy buscando la mejor respuesta "teórica" si existe, ya que sé que ambas soluciones son posibles.
Dos desventajas muy obvias para jugar con punteros: 1) Yo mismo debo administrar la asignación / desasignación de estos objetos en un ámbito más allá del STL. 2) No puedo crear un objeto temporal en la pila y agregarlo a mis contenedores.
¿Me falta algo más?
Respuestas:
Dado que las personas están hablando de la eficiencia del uso de punteros.
Si está considerando usar un std :: vector y si las actualizaciones son pocas y a menudo itera sobre su colección y es un objeto de almacenamiento no polimórfico, las "copias" serán más eficientes ya que obtendrá una mejor localidad de referencia.
Otoh, si las actualizaciones son comunes, el almacenamiento de punteros ahorrará los costos de copia / reubicación.
fuente
Esto realmente depende de tu situación.
Si sus objetos son pequeños y hacer una copia del objeto es liviano, entonces almacenar los datos dentro de un contenedor stl es sencillo y fácil de administrar en mi opinión porque no tiene que preocuparse por la administración de por vida.
Si sus objetos son grandes, y tener un constructor predeterminado no tiene sentido, o las copias de los objetos son costosas, entonces el almacenamiento con punteros es probablemente el camino a seguir.
Si decide utilizar punteros a los objetos, eche un vistazo a la biblioteca de contenedores de punteros de impulso . Esta biblioteca de impulso envuelve todos los contenedores STL para su uso con objetos asignados dinámicamente.
Cada contenedor de puntero (por ejemplo, ptr_vector) toma posesión de un objeto cuando se agrega al contenedor y administra la vida útil de esos objetos por usted. También tiene acceso a todos los elementos en un contenedor ptr_ por referencia. Esto te permite hacer cosas como
Estas clases envuelven los contenedores STL y funcionan con todos los algoritmos STL, lo cual es realmente útil.
También hay facilidades para transferir la propiedad de un puntero en el contenedor a la persona que llama (mediante la función de liberación en la mayoría de los contenedores).
fuente
Si está almacenando objetos polimórficos, siempre debe usar una colección de punteros de clase base.
Es decir, si planea almacenar diferentes tipos derivados en su colección, debe almacenar punteros o ser devorado por el demonio de corte.
fuente
Lamento saltar en 3 años después del evento, pero una nota de advertencia aquí ...
En mi último gran proyecto, mi estructura de datos central era un conjunto de objetos bastante sencillos. Aproximadamente un año después del proyecto, a medida que evolucionaban los requisitos, me di cuenta de que el objeto realmente tenía que ser polimórfico. Tomó algunas semanas de cirugía cerebral difícil y desagradable arreglar la estructura de datos para que fuera un conjunto de punteros de clase base y manejar todo el daño colateral en el almacenamiento de objetos, el lanzamiento, etc. Me tomó un par de meses convencerme de que el nuevo código estaba funcionando. Por cierto, esto me hizo pensar mucho sobre cuán bien diseñado está el modelo de objetos de C ++.
En mi gran proyecto actual, mi estructura de datos central es un conjunto de objetos bastante sencillos. Aproximadamente un año después del proyecto (que es hoy), me di cuenta de que el objeto realmente necesita ser polimórfico. De vuelta a la red, encontré este hilo y encontré el enlace de Nick a la biblioteca del contenedor de punteros Boost. Esto es exactamente lo que tuve que escribir la última vez para arreglar todo, así que lo intentaré esta vez.
La moraleja, para mí, de todos modos: si su especificación no está 100% moldeada en piedra, busque consejos, y puede ahorrarse mucho trabajo más adelante.
fuente
¿Por qué no obtener lo mejor de ambos mundos? Haga un contenedor de punteros inteligentes (como
boost::shared_ptr
ostd::shared_ptr
). No tiene que administrar la memoria, y no tiene que lidiar con operaciones de copia grandes.fuente
Generalmente, almacenar los objetos directamente en el contenedor STL es mejor, ya que es más simple, más eficiente y más fácil de usar.
Si su propio objeto tiene una sintaxis no copiable o es un tipo base abstracto, necesitará almacenar punteros (lo más fácil es usar shared_ptr)
fuente
Parece que tienes una buena comprensión de la diferencia. Si los objetos son pequeños y fáciles de copiar, almacénelos.
Si no, pensaría en almacenar punteros inteligentes (no auto_ptr, un puntero inteligente de recuento de referencias) a los que asigne en el montón. Obviamente, si opta por punteros inteligentes, entonces no puede almacenar objetos asignados a la pila temporal (como ha dicho).
@ Torbjörn hace un buen punto sobre el corte.
fuente
one
aanother
liberará la referencia deone
y cambiaráone
.El uso de punteros será más eficiente ya que los contenedores solo copiarán punteros en lugar de objetos completos.
Aquí hay información útil sobre contenedores STL y punteros inteligentes:
¿Por qué está mal usar std :: auto_ptr <> con contenedores estándar?
fuente
Si se hace referencia a los objetos en otra parte del código, almacénelos en un vector de boost :: shared_ptr. Esto garantiza que los punteros al objeto seguirán siendo válidos si cambia el tamaño del vector.
Es decir:
Si nadie más almacena punteros a los objetos, o la lista no crece y se contrae, simplemente almacene como objetos antiguos:
fuente
Esta pregunta me ha estado molestando por un tiempo.
Me inclino por almacenar punteros, pero tengo algunos requisitos adicionales (SWIG lua wrappers) que podrían no aplicarse a usted.
El punto más importante en esta publicación es probarlo usted mismo , usando sus objetos
Lo hice hoy para probar la velocidad de llamar a una función miembro en una colección de 10 millones de objetos, 500 veces.
La función actualiza x e y en función de xdir e ydir (todas las variables miembro flotante).
Utilicé una std :: list para contener ambos tipos de objetos, y descubrí que almacenar el objeto en la lista es un poco más rápido que usar un puntero. Por otro lado, el rendimiento fue muy cercano, por lo que se trata de cómo se utilizarán en su aplicación.
Como referencia, con -O3 en mi hardware, los punteros tardaron 41 segundos en completarse y los objetos sin procesar tardaron 30 segundos en completarse.
fuente