c++ - significado - Punteros, punteros inteligentes o punteros compartidos?
punteros c++ (5)
Esta pregunta ya tiene una respuesta aquí:
Estoy programando con punteros normales, pero he oído hablar de bibliotecas como Boost que implementan punteros inteligentes. También he visto que en el motor de renderizado Ogre3D hay un uso profundo de punteros compartidos.
¿Cuál es exactamente la diferencia entre los tres, y debería seguir usando solo un tipo de ellos?
Los indicadores inteligentes se limpiarán ellos mismos una vez que salgan del alcance (eliminando así el temor a la mayoría de las pérdidas de memoria). Los punteros compartidos son punteros inteligentes que cuentan el número de instancias del puntero y solo limpian la memoria cuando el recuento llega a cero. En general, solo use punteros compartidos (pero asegúrese de usar el tipo correcto; hay uno diferente para las matrices). Ellos tienen mucho que ver con RAII .
Para agregar un poco a la respuesta de Sydius, los indicadores inteligentes a menudo ofrecen una solución más estable al detectar muchos errores fáciles de cometer. Los indicadores sin formato tendrán algunas ventajas de rendimiento y pueden ser más flexibles en determinadas circunstancias. También puede verse obligado a utilizar punteros sin formato al vincular a ciertas bibliotecas de terceros.
Para evitar fugas de memoria, puede utilizar punteros inteligentes siempre que sea posible. Básicamente, hay 2 tipos diferentes de punteros inteligentes en C ++
- Referencia contada (por ejemplo, boost :: shared_ptr / std :: tr1: shared_ptr)
- sin referencia contada (por ejemplo, boost :: scoped_ptr / std :: auto_ptr)
La diferencia principal es que los punteros inteligentes contados de referencia se pueden copiar (y usar en std :: containers) mientras que scoped_ptr no. Los punteros contados no de referencia casi no tienen gastos generales ni gastos generales. El recuento de referencias siempre introduce algún tipo de sobrecarga.
(Sugiero evitar auto_ptr, tiene algunos defectos graves si se usa incorrectamente)
Sydius describió los tipos bastante bien:
- Los punteros normales son solo eso: señalan algo en la memoria en alguna parte. ¿A quién pertenece? Solo los comentarios te lo harán saber. ¿Quién lo libera? Esperemos que el dueño en algún momento.
- Los punteros inteligentes son un término general que cubre muchos tipos; Asumiré que querías un puntero con alcance que usa el patrón RAII . Es un objeto asignado a la pila que envuelve un puntero; cuando sale del alcance, llama a eliminar en el puntero que envuelve. "Posee" el puntero contenido en que está a cargo de eliminarlo en algún momento. Le permiten obtener una referencia en bruto del puntero que envuelven para pasar a otros métodos, así como también soltar el puntero, permitiendo que otra persona lo posea. Copiarlos no tiene sentido.
- Los punteros compartidos es un objeto asignado a la pila que envuelve un puntero para que no tenga que saber a quién pertenece. Cuando se destruye el último puntero compartido para un objeto en la memoria, también se eliminará el puntero envuelto.
¿Qué tal cuando deberías usarlos? Harás un uso intensivo de los punteros de alcance o los punteros compartidos. ¿Cuántos hilos se están ejecutando en su aplicación? Si la respuesta es "potencialmente mucho", los indicadores compartidos pueden convertirse en un cuello de botella de rendimiento si se usan en todas partes. La razón es que crear / copiar / destruir un puntero compartido debe ser una operación atómica, y esto puede dificultar el rendimiento si tiene muchos subprocesos en ejecución. Sin embargo, no siempre será el caso; solo las pruebas le informarán con certeza.
Existe un argumento (que me gusta) contra punteros compartidos: al usarlos, les está permitiendo a los programadores ignorar quién posee un puntero. Esto puede llevar a situaciones complicadas con referencias circulares (Java las detectará, pero los punteros compartidos no pueden) o la holgazanería del programador general en una gran base de código.
Hay dos razones para usar punteros con alcance. La primera es para operaciones sencillas de seguridad y limpieza de excepciones: si desea garantizar que un objeto se limpia sin importar las excepciones, y no desea apilar la asignación de ese objeto, colóquelo en un puntero de ámbito. Si la operación es exitosa, puede transferirla a un puntero compartido, pero mientras tanto, guarde la sobrecarga con un puntero de alcance.
El otro caso es cuando desea una propiedad clara del objeto. Algunos equipos prefieren esto, otros no. Por ejemplo, una estructura de datos puede devolver punteros a objetos internos. Debajo de un puntero de ámbito, devolvería un puntero sin formato o una referencia que debería tratarse como una referencia débil: es un error acceder a ese puntero después de que la estructura de datos que lo posee se destruye y es un error eliminarlo. Bajo un puntero compartido, el objeto propietario no puede destruir los datos internos que devolvió si alguien todavía tiene un control sobre él, esto podría dejar los recursos abiertos durante mucho más tiempo de lo necesario o mucho peor dependiendo del código.
el término "puntero inteligente" incluye punteros compartidos, punteros automáticos, punteros de bloqueo y otros. querías decir auto puntero (más ambiguamente conocido como "poseer puntero"), no puntero inteligente.
Los consejos tontos (T *) nunca son la mejor solución. Te obligan a hacer una gestión de memoria explícita, que es prolija, propensa a errores y, en ocasiones, casi imposible. Pero más importante aún, no señalan tu intención.
Los punteros automáticos eliminan la punta en el momento de la destrucción. Para matrices, prefiera encapsulaciones como vector y deque. Para otros objetos, muy raramente existe la necesidad de almacenarlos en el montón: solo use los locales y la composición de objetos. Sin embargo, la necesidad de punteros automáticos surge con las funciones que devuelven los punteros del montón, como las fábricas y los retornos polimórficos.
Los punteros compartidos eliminan el puntero cuando se destruye el último puntero compartido. Esto es útil cuando se desea un esquema de almacenamiento abierto y sin complicaciones, donde la vida útil esperada y la propiedad pueden variar ampliamente según la situación. Debido a la necesidad de mantener un contador (atómico), son un poco más lentos que los punteros automáticos. Algunos dicen en broma que los indicadores compartidos son para personas que no pueden diseñar sistemas, juzguen por sí mismos.
Para una contraparte esencial de punteros compartidos, busque punteros débiles también.