Articulo de referencia

puntero inteligente

En informática , un puntero inteligente es un tipo de dato abstracto que simula un puntero a la vez que proporciona características adicionales, como la gestión automática de me...

En informática , un puntero inteligente es un tipo de dato abstracto que simula un puntero a la vez que proporciona características adicionales, como la gestión automática de memoria o la comprobación de límites . Estas características están diseñadas para reducir los errores causados ​​por el mal uso de punteros, manteniendo la eficiencia. Los punteros inteligentes suelen llevar un registro de la memoria a la que apuntan y también pueden utilizarse para gestionar otros recursos, como conexiones de red y descriptores de archivos . Los punteros inteligentes se popularizaron por primera vez en el lenguaje de programación C++ durante la primera mitad de la década de 1990 como respuesta a las críticas sobre la falta de recolección automática de basura en C++ . [ 1 ] [ 2 ] Rust , que evita los punteros sin procesar y utiliza la propiedad para determinar la duración de los objetos, también tiene punteros inteligentes.

El uso indebido de punteros puede ser una fuente importante de errores. Los punteros inteligentes previenen la mayoría de las fugas de memoria al automatizar la liberación de memoria. En términos más generales, automatizan la destrucción de objetos : un objeto controlado por un puntero inteligente se destruye automáticamente ( se finaliza y luego se libera) cuando se destruye el último (o único) propietario del objeto, por ejemplo, porque el propietario es una variable local y la ejecución sale del ámbito de la variable . Los punteros inteligentes también eliminan los punteros colgantes al posponer la destrucción hasta que el objeto ya no esté en uso.

Si un lenguaje admite la recolección automática de basura (por ejemplo, Java o C# ), entonces los punteros inteligentes no son necesarios para la recuperación de memoria ni para los aspectos de seguridad de la administración de memoria, pero sí son útiles para otros fines, como la administración de la residencia de estructuras de datos en caché y la administración de recursos de objetos como descriptores de archivos o sockets de red . Java, aunque no tiene una API de punteros, cuenta con conceptos similares para el manejo de referencias.

Several types of smart pointers exist. Some work with reference counting, others by assigning ownership of an object to one pointer.

History

Even though C++ popularized the concept of smart pointers, especially the reference-counted variety,[3] the immediate predecessor of one of the languages that inspired C++'s design had reference-counted references built into the language. C++ was inspired in part by Simula67.[4] Simula67's ancestor was Simula I. Insofar as Simula I's element is analogous to C++'s pointer without null, and insofar as Simula I's process with a dummy-statement as its activity body is analogous to C++'s struct (which itself is analogous to C. A. R. Hoare's record in then-contemporary 1960s work), Simula I had reference counted elements (i.e., pointer-expressions that house indirection) to processes (i.e., records) no later than September 1965, as shown in the quoted paragraphs below.[5]

Processes can be referenced individually. Physically, a process reference is a pointer to an area of memory containing the data local to the process and some additional information defining its current state of execution. However, for reasons stated in the Section 2.2 process references are always indirect, through items called elements. Formally a reference to a process is the value of an expression of type element. … element values can be stored and retrieved by assignments and references to element variables and by other means. The language contains a mechanism for making the attributes of a process accessible from the outside, i.e., from within other processes. This is called remote accessing. A process is thus a referenceable data structure.

It is worth noticing the similarity between a process whose activity body is a dummy statement, and the record concept recently proposed by C. A. R. Hoare and N. Wirth

Because C++ borrowed Simula's approach to memory allocation—the new keyword when allocating a process/record to obtain a fresh element to that process/record—it is not surprising that C++ eventually resurrected Simula's reference-counted smart-pointer mechanism within element as well.

Features

En C++ , un puntero inteligente se implementa como una clase plantilla que imita, mediante la sobrecarga de operadores , el comportamiento de un puntero tradicional (sin procesar) , (por ejemplo, desreferenciación, asignación) al tiempo que proporciona características adicionales de gestión de memoria.

Los punteros inteligentes facilitan la programación intencionada al especificar, en el tipo de dato, cómo se gestionará la memoria del objeto al que apunta el puntero. Por ejemplo, si una función de C++ devuelve un puntero, no hay forma de saber si quien la llama debe liberar la memoria del objeto al que apunta una vez que haya terminado de usar la información.

SomeType * ambiguousFunction (); // ¿Qué se debe hacer con el resultado?

Tradicionalmente, se han utilizado convenciones de nomenclatura para resolver la ambigüedad, [ 6 ] que es un enfoque propenso a errores y laborioso. C++11 introdujo una forma de garantizar una gestión de memoria correcta en este caso declarando que la función devuelva un std::unique_ptr,

unique_ptr < SomeType > ObviouslyFunction ();

La declaración del tipo de retorno de la función como unique_ptrexplicita el hecho de que quien la llama toma posesión del resultado, y el entorno de ejecución de C++ garantiza que la memoria se recuperará automáticamente. Antes de C++11 , unique_ptrse podía reemplazar con auto_ptr , que ahora está obsoleto.

Creación de nuevos objetos

Para facilitar la asignación de un std::shared_ptr<SomeType>, C++11 introdujo:

shared_ptr < SomeType > s = std :: make_shared < SomeType > ( constructor , parameters , here );

y de manera similar std::unique_ptr<SomeType>, desde C++14 se puede usar:

unique_ptr < SomeType > u = std :: make_unique < SomeType > ( constructor , parameters , here );

En casi todas las circunstancias, se prefiere utilizar estas funciones en lugar de la newpalabra clave. [ 7 ]

Punteros únicos

C++11 introduce std::unique_ptr, definido en el encabezado <memory>. [ 8 ]

A unique_ptres un contenedor para un puntero sin formato, del cual unique_ptrse dice que es propietario. A unique_ptrimpide explícitamente la copia de su puntero contenido (como ocurriría con una asignación normal), pero la std::movefunción puede usarse para transferir la propiedad del puntero contenido a otro unique_ptr. A unique_ptrno puede copiarse porque su constructor de copia y sus operadores de asignación se eliminan explícitamente.

importar std ;usando std :: unique_ptr ;unique_ptr < int > p1 ( new int ( 5 )); unique_ptr < int > p2 = p1 ; // Error de compilación. unique_ptr < int > p3 = std :: move ( p1 ); // Transfiere la propiedad. p3 ahora posee la memoria y p1 se establece en nullptr.p3.reset (); // Borra la memoria. p1.reset ( ) ; // No hace nada.

std::auto_ptrestá obsoleto en C++11 y se eliminó por completo en C++17 . El constructor de copia y los operadores de asignación de auto_ptrno copian realmente el puntero almacenado. En cambio, lo transfieren , dejando el objeto anterior auto_ptrvacío. Esta era una forma de implementar la propiedad estricta, de modo que solo un auto_ptrobjeto puede poseer el puntero en un momento dado. Esto significa que auto_ptrno debe usarse donde se necesiten semánticas de copia. [ 9 ] Dado que auto_ptrya existía con su semántica de copia, no se podía actualizar a un puntero de solo movimiento sin romper la compatibilidad con versiones anteriores con el código existente.

El equivalente en Rust de los punteros únicos es std::boxed::Box, que tiene propiedad única de un objeto asignado en el montón. [ 10 ] En versiones anteriores de Rust, también había un std::ptr::Uniqueque envolvía a los no nulos sin procesar *mut T. [ 11 ]

Es posible utilizar " punteros void inteligentes " utilizando std::unique_ptrsu segundo parámetro de plantilla Deleter, que almacena un tipo de desasignador.

usando std :: unique_ptr ;struct MyDeleter { void operator ()( void * p ) const { delete static_cast < int *> ( p ); } };int main () { unique_ptr < void , MyDeleter > myPointer ( new int ( 42 ), MyDeleter ()); }

Punteros compartidos y punteros débiles

C++11 introduce std::shared_ptry std::weak_ptr, definidos en el encabezado <memory>. [ 8 ] C++11 también introduce std::make_shared( std::make_uniquese introdujo en C++14) para asignar de forma segura memoria dinámica en el paradigma RAII . [ 12 ]

A shared_ptres un contenedor para un puntero sin formato . Mantiene la propiedad del conteo de referencias de su puntero contenido en cooperación con todas las copias de shared_ptr. Un objeto referenciado por el puntero sin formato contenido se destruirá cuando y solo cuando todas las copias de shared_ptrhayan sido destruidas.

importar std ;usando std :: shared_ptr ;shared_ptr < int > p0 ( new int ( 5 )); // Válido, asigna 1 entero y lo inicializa con el valor 5. shared_ptr < int [] > p1 ( new int [ 5 ]); // Válido, asigna 5 enteros. shared_ptr < int [] > p2 = p1 ; // Ahora ambos poseen la memoria.p1.reset (); // La memoria aún existe, debido a p2. p2.reset ( ); // Libera la memoria, ya que nadie más posee la memoria.

A weak_ptres un contenedor para un puntero sin formato. Se crea como una copia de un shared_ptr. La existencia o destrucción de weak_ptrcopias de un shared_ptrno afecta a shared_ptrni a sus otras copias. Después de que todas las copias de un shared_ptrse hayan destruido, todas weak_ptrlas copias quedan vacías.

importar std ;using std :: shared_ptr ; using std :: weak_ptr ;shared_ptr < int > p1 = std :: make_shared < int > ( 5 ); weak_ptr < int > wp1 { p1 }; // p1 posee la memoria.{ shared_ptr < int > p2 = wp1 . lock (); // Ahora p1 y p2 poseen la memoria. // p2 se inicializa desde un puntero débil, por lo que hay que comprobar si la // memoria todavía existe. if ( p2 ) { useSomePointer ( p2 ); } } // p2 se destruye. La memoria es propiedad de p1.p1.reset ( ); // Libera la memoria .shared_ptr < int > p3 = wp1 . lock (); // La memoria se ha agotado, por lo que obtenemos un shared_ptr vacío. if ( p3 ) { // El código no se ejecutará useLivePointer ( p3 ); }

Debido a que la implementación shared_ptrutiliza el conteo de referencias , las referencias circulares son potencialmente un problema. Una shared_ptrcadena circular se puede romper cambiando el código de modo que una de las referencias sea un weak_ptr.

Varios hilos pueden acceder simultáneamente y de forma segura a diferentes objetos shared_ptrque weak_ptrapuntan al mismo objeto. [ 13 ]

El objeto al que se hace referencia debe protegerse por separado para garantizar la seguridad de los hilos .

shared_ptry weak_ptrse basan en versiones utilizadas por las bibliotecas Boost . El Informe Técnico 1 (TR1) de C++ las introdujo por primera vez en el estándar como utilidades generales , pero C++11 añade más funciones, en línea con la versión de Boost.

En Java, cada objeto es, en efecto, una referencia compartida, y la Máquina Virtual de Java (JVM) controla la accesibilidad de los objetos. Rust tiene dos tipos de punteros compartidos: std::rc::Rcuno con conteo de referencias y de un solo hilo, y std::sync::Arcotro con conteo de referencias atómico y seguro para hilos.

Java tiene un concepto equivalente a los punteros débiles java.lang.ref.WeakReference(implementando una referencia débil ), que no aumenta el contador de referencias de un objeto y puede comprobar que un objeto aún existe usando WeakReference::get. Java de manera similar tiene el java.lang.ref.PhantomReference(implementando una referencia fantasma ), usado con un java.lang.ref.ReferenceQueue, para realizar acciones de limpieza después de que un objeto sea recolectado por el recolector de basura, pero antes de la finalización . A diferencia de WeakReference), PhantomReferenceno puede acceder realmente al objeto. java.lang.ref.SoftReference, por otro lado, se limpian según la discreción del recolector de basura. Rust tiene un std::rc::Weakpara una referencia débil, no propietaria, que se crea a partir de un Rco Arcusando downgrade(). [ 14 ]

Indicadores de peligro

A partir de C++26 , se define un nuevo puntero en <hazard_pointer>, el puntero de riesgo ( std::hazard_pointer). Es un puntero de un solo escritor y múltiples lectores que puede ser propiedad de como máximo un hilo en cualquier momento.

El puntero de riesgo ya existía previamente en algunas bibliotecas de terceros. [ 15 ]

Otros tipos de punteros inteligentes

Hay otros tipos de punteros inteligentes (que no están en el estándar de C++) implementados en bibliotecas populares de C++ o STL personalizadas , algunos ejemplos incluyen el puntero intrusivo. [ 16 ] [ 17 ]

Véase también

Referencias

  1. ^ Kline, Marshall (septiembre de 1997). "Secciones de C++ FAQs Lite sobre punteros inteligentes con conteo de referencias y semántica de referencias de copia en escritura en las FAQ de administración de freestore" . cis.usouthal.edu . Recuperado el 6 de abril de 2018 .
  2. ^ Colvin, Gregory (1994). "Propuesta para estandarizar counted_ptr en la biblioteca estándar de C++" (PDF) . open-std.org . Consultado el 6 de abril de 2018 .
  3. ^ Klabnik, Steve; Nichols, Carol (2023) [2018]. "15. Punteros inteligentes". El lenguaje de programación Rust (2.ª ed.). San Francisco, California, EE. UU.: No Starch Press, Inc. págs.  315–351 . ISBN 978-1-7185-0310-6.(xxix+1+527+3 páginas)
  4. ^ Stroustrup, Bjarne. "Una historia de C++: 1979–1991" (PDF) . Consultado el 6 de abril de 2018 .
  5. ^ Dahl, Ole-Johan; Nygaard, Kristen (septiembre de 1966). "SIMULA: un lenguaje de simulación basado en ALGOL" (PDF) . folk.uio.no. ​Consultado el 6 de abril de 2018 .
  6. ^ "Guía de Talent para el diseño de programas, sección "Utilice nombres especiales para copiar, crear y adoptar rutinas" .
  7. ^ Sutter, Herb (2013-04-20). "Informe de viaje: Reunión de primavera de ISO C++ 2013" . isocpp.org . Recuperado el 14 de junio de 2013 .
  8. ^ a b ISO 14882:2011 20.7.1
  9. ^ Estándar de codificación segura CERT C++
  10. ^ "Box en std::boxed" . doc.rust-lang.org . 2025-08-04.
  11. ^ "std::ptr::Unique" . web.mit.edu . 2025-09-11.
  12. ^ ISO 14882:2014 20.7.1
  13. ^ "seguridad de subprocesos de boost::shared_ptr" .(Nota: No cubre formalmente std::shared_ptr, pero se cree que tiene las mismas limitaciones de subprocesos).
  14. ^ "Débil en std::rc" . doc.rust-lang.org . 2025-08-04.
  15. ^ "folly/Hazptr.h en main · facebook/folly" . github.com .
  16. ^ "Boost.SmartPtr: La biblioteca de punteros inteligentes - 1.81.0" . boost.org .
  17. ^ "EASTL/intrusive_ptr.h en master · electronicarts/EASTL" . github.com .

Lecturas adicionales

  • countptr.hpp . La biblioteca estándar de C++: un tutorial y referencia por Nicolai M. Josuttis
  • Punteros inteligentes de Boost
  • Punteros inteligentes en Delphi
  • Punteros inteligentes en Rust
  • Punteros inteligentes en C++ moderno
Obtenido de " https://en.wikipedia.org/w/index.php?title=Smart_pointer&oldid=1323356106 "