punteros puntero objeto declaracion c++ stl pointers

c++ - declaracion - ¿Debo almacenar objetos enteros o punteros a los objetos en contenedores?



punteros c++ (10)

¿Por qué no obtener lo mejor de ambos mundos: hacer 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.

Diseñando un nuevo sistema desde cero. Usaré el STL para almacenar listas y mapas de ciertos objetos de larga duración.

Pregunta: ¿Debo asegurarme de que mis objetos tengan constructores de copias y almacenar copias de los objetos dentro de mis contenedores STL, o generalmente es 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 corto 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) Debo administrar la asignación / desasignación de estos objetos yo mismo en un alcance 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 pierdo?


Dado que la gente no deja de mencionar la eficiencia de usar punteros.

Si está considerando usar un std :: vector y si las actualizaciones son pocas y con frecuencia itera sobre su colección y es un objeto de almacenamiento de tipo 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 guardará los costos de copia / reubicación.



En general, almacenar los objetos directamente en el contenedor STL es lo mejor ya que es el más simple, el más eficiente y el más fácil de usar.

Si su objeto en sí tiene sintaxis no copiable o es un tipo de base abstracta, necesitará almacenar punteros (lo más fácil es usar shared_ptr)


Esta pregunta me ha estado molestando por un tiempo.

Me inclino por el almacenamiento de punteros, pero tengo algunos requisitos adicionales (envolturas SWIG lua) que pueden no aplicarse en su caso.

El punto más importante en esta publicación es probarlo usted mismo , utilizando 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 xey basándose en xdir e ydir (todas las variables de miembros flotantes).

Usé una lista estándar para contener ambos tipos de objetos, y encontré que almacenar el objeto en la lista es ligeramente más rápido que usar un puntero. Por otro lado, el rendimiento fue muy cercano, por lo que se reduce a la forma en que 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.


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 más fácil de manejar, en mi opinión, porque no tiene que preocuparse por la administración de por vida.

Si los objetos son grandes, y tener un constructor predeterminado no tiene sentido, o las copias de los objetos son caras, entonces almacenar con punteros es probablemente el camino a seguir.

Si decide usar punteros a los objetos, eche un vistazo a la Biblioteca de Boost Pointer Container . Esta biblioteca de impulso envuelve todos los contenedores STL para su uso con objetos dinámicamente asignados.

Cada contenedor de puntero (por ejemplo, ptr_vector) toma posesión de un objeto cuando se agrega al contenedor y administra el tiempo de vida de esos objetos por usted. También accede 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 que es realmente útil.

También hay instalaciones 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).


Parece que tienes una buena comprensión de la diferencia. Si los objetos son pequeños y fáciles de copiar, almacénelos.

De lo contrario, pensaría en almacenar punteros inteligentes (no auto_ptr, un puntero inteligente de recuento inteligente) a los que asignas en el montón. Obviamente, si opta por punteros inteligentes, entonces no puede almacenar objetos asignados a la pila de temperatura (como ha dicho).

@ Torbjörn hace un buen punto acerca de cortar.


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 central de datos era un conjunto de objetos bastante sencillos. Alrededor de un año en el proyecto, a medida que evolucionaban los requisitos, me di cuenta de que el objeto realmente necesitaba ser polimórfico. Se necesitaron unas semanas de cirugía cerebral difícil y desagradable para arreglar la estructura de datos para que sea un conjunto de punteros de clase base, y para manejar todo el daño colateral en el almacenamiento de objetos, la fundición, etc. Me llevó un par de meses convencerme de que el nuevo código funcionaba. 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. Alrededor de un año en el 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 del puntero Boost. Esto es exactamente lo que tuve que escribir la última vez para arreglar todo, así que esta vez lo intentaré.

La moraleja, para mí, de todos modos: si su especificación no está 100% moldeada en piedra, busque indicadores, y posiblemente se ahorrará mucho trabajo más adelante.


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 comido por el slicing deamon.


Si hay que hacer referencia a los objetos en otra parte del código, guárdelos en un vector de boost :: shared_ptr. Esto asegura 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 simples:

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