Pregunta

Diseño de 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 & amp; ¿Me examino y solo almaceno los punteros a esos objetos en mis contenedores STL?

Me doy cuenta de que esto es algo corto en detalles, pero estoy buscando el " teórico " mejor respuesta si existe, ya que sé que ambas soluciones son posibles.

Dos desventajas muy obvias para jugar con punteros: 1) Debo gestionar la asignación / desasignación de estos objetos yo mismo en un ámbito más allá del STL. 2) No puedo crear un objeto temporal en la pila y agregarlo a mis contenedores.

¿Hay algo más que me falta?

¿Fue útil?

Solución

Dado que las personas están aprovechando la eficacia del uso de punteros.

Si está considerando usar un vector std :: y si las actualizaciones son pocas y a menudo itera sobre su colección y es un objeto de almacenamiento de tipo no polimórfico " copias " será más eficiente ya que obtendrá una mejor localidad de referencia.

Otoh, si las actualizaciones son comunes, los punteros de almacenamiento ahorrarán los costos de copia / reubicación.

Otros consejos

Esto realmente depende de su 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 almacenar con punteros es probablemente el camino a seguir.

Si decide usar punteros a objetos, eche un vistazo a Boost Pointer Container Library . 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

class BigExpensive { ... }

// create a pointer vector
ptr_vector<BigExpensive> bigVector;
bigVector.push_back( new BigExpensive( "Lexus", 57700 ) );
bigVector.push_back( new BigExpensive( "House", 15000000 );

// get a reference to the first element
MyClass& expensiveItem = bigList[0];
expensiveItem.sell();

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 (a través de la función de liberación en la mayoría de los contenedores).

Si está almacenando objetos polimórficos, siempre necesita 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.

Perdón por 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 evolucionaron los requisitos, me di cuenta de que el objeto realmente tenía que ser polimórfico. Se necesitaron algunas semanas de cirugía cerebral difícil y desagradable para arreglar la estructura de datos para que fuera un conjunto de punteros de clase base, y para 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 sucede 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 tarde.

¿Por qué no obtener lo mejor de ambos mundos? Haga un contenedor de punteros inteligentes (como boost::shared_ptr o std::shared_ptr ) No tiene que administrar la memoria y no tiene que lidiar con operaciones de copia grandes.

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)

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 & # 246; rn hace un buen punto sobre el corte.

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é es incorrecto usar std? :: auto_ptr < > con contenedores estándar?

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:

std::vector<boost::shared_ptr<protocol> > protocols;
...
connection c(protocols[0].get()); // pointer to protocol stays valid even if resized

Si nadie más almacena punteros a los objetos, o la lista no crece y se contrae, simplemente almacene como objetos antiguos:

std::vector<protocol> protocols;
connection c(protocols[0]); // value-semantics, takes a copy of the protocol

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

Hice esto 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 basándose en xdir e ydir (todas las variables miembro flotante).

Utilicé una lista std :: 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 en bruto tardaron 30 segundos en completarse.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top