Requisito previo: Punteros en C++
Los punteros se utilizan para acceder a recursos externos al programa, como la memoria dinámica. Entonces, para acceder a la memoria del montón (si se crea algo dentro de la memoria del montón), se utilizan punteros. Al acceder a cualquier recurso externo, simplemente utilizamos una copia del recurso. Si le hacemos algún cambio, simplemente lo cambiamos en la versión copiada. Pero, si usamos un puntero al recurso, podremos cambiar el recurso original.
Problemas con los punteros normales
Algunos problemas con punteros normales en C++ son los siguientes:
- Pérdidas de memoria: esto ocurre cuando un programa asigna memoria repetidamente pero nunca la libera. Esto conduce a un consumo excesivo de memoria y, finalmente, a un fallo del sistema. Punteros colgantes: un puntero colgante es un puntero que se produce en el momento en que el objeto se desasigna de la memoria sin modificar el valor del puntero. Punteros salvajes: Los punteros salvajes son punteros que se declaran y se les asigna memoria, pero el puntero nunca se inicializa para apuntar a ningún objeto o dirección válido. Inconsistencia de datos: la inconsistencia de datos ocurre cuando algunos datos se almacenan en la memoria pero no se actualizan de manera consistente. Desbordamiento de búfer: cuando se utiliza un puntero para escribir datos en una dirección de memoria que está fuera del bloque de memoria asignado. Esto conduce a la corrupción de datos que pueden ser explotados por atacantes malintencionados.
Ejemplo:
C++
// C++ program to demonstrate working of a Pointers> #include> using> namespace> std;> class> Rectangle {> private>:> >int> length;> >int> breadth;> };> void> fun()> {> >// By taking a pointer p and> >// dynamically creating object> >// of class rectangle> >Rectangle* p =>new> Rectangle();> }> int> main()> {> >// Infinite Loop> >while> (1) {> >fun();> >}> }> |
>
>
Producción
Memory limit exceeded>
Explicación: En función divertido , crea un puntero que apunta al Rectángulo objeto. El objeto Rectángulo contiene dos números enteros, longitud, y amplitud . cuando la función divertido termina, p será destruido ya que es una variable local. Pero la memoria que consumió no será desasignada porque olvidamos usarla. eliminar p; al final de la función. Eso significa que la memoria no podrá ser utilizada por otros recursos. Pero ya no necesitamos la variable, necesitamos la memoria.
En función, principal , divertido se llama en un bucle infinito. Eso significa que seguirá creando pag . Asignará más y más memoria, pero no la liberará porque no la desasignamos. La memoria desperdiciada no se puede volver a utilizar. Lo cual es una pérdida de memoria. La totalidad montón La memoria puede volverse inútil por este motivo.
Punteros inteligentes
Como sabemos inconscientemente, no desasignar un puntero provoca una pérdida de memoria que puede provocar un bloqueo del programa. Idiomas Java, C# tiene Mecanismos de recolección de basura para desasignar inteligentemente la memoria no utilizada para usarla nuevamente. El programador no tiene que preocuparse por pérdidas de memoria. C++ presenta su propio mecanismo que es Puntero inteligente . Cuando el objeto se destruye, también se libera la memoria. Por lo tanto, no es necesario que lo eliminemos ya que Smart Pointer se encargará de ello.
A Puntero inteligente es una clase contenedora sobre un puntero con un operador como * y -> sobrecargado. Los objetos de la clase de puntero inteligente parecen punteros normales. Pero a diferencia punteros normales, puede desasignar y liberar memoria de objetos destruidos.
La idea es tomar una clase con un puntero, destructor, y operadores sobrecargados como * y -> . Dado que el destructor se llama automáticamente cuando un objeto sale del alcance, la memoria asignada dinámicamente se eliminará automáticamente (o se puede disminuir el recuento de referencias).
Ejemplo:
C++
// C++ program to demonstrate the working of Smart Pointer> #include> using> namespace> std;> class> SmartPtr {> >int>* ptr;>// Actual pointer> public>:> >// Constructor: Refer> >// techcodeview.com for use of> >// explicit keyword> >explicit> SmartPtr(>int>* p = NULL) { ptr = p; }> >// Destructor> >~SmartPtr() {>delete> (ptr); }> >// Overloading dereferencing operator> >int>& operator*() {>return> *ptr; }> };> int> main()> {> >SmartPtr ptr(>new> int>());> >*ptr = 20;> >cout << *ptr;> >// We don't need to call delete ptr: when the object> >// ptr goes out of scope, the destructor for it is> >// automatically called and destructor does delete ptr.> >return> 0;> }> |
>
>Producción
20>
Diferencia entre punteros y punteros inteligentes
| Puntero | Puntero inteligente |
|---|---|
| Un puntero es una variable que mantiene una dirección de memoria, así como información de tipo de datos sobre esa ubicación de memoria. Un puntero es una variable que apunta a algo en la memoria. | Es un objeto asignado a la pila que envuelve el puntero. Los punteros inteligentes, en términos sencillos, son clases que envuelven un puntero o punteros con alcance. |
| No se destruye de ninguna forma cuando sale de su alcance. | Se destruye a sí mismo cuando sale de su alcance. |
| Los punteros no son tan eficientes porque no admiten ninguna otra función. | Los punteros inteligentes son más eficientes ya que tienen una función adicional de gestión de memoria. |
| Son muy manuales y centrados en la mano de obra. | Son de naturaleza automática/preprogramada. |
Nota: Esto sólo funciona para En t . Entonces, ¿tendremos que crear un puntero inteligente para cada objeto? No , hay una solución, Plantilla . En el siguiente código como puedes ver t puede ser de cualquier tipo.
Linux ejecuta cmd
Ejemplo:
C++
// C++ program to demonstrate the working of Template and> // overcome the issues which we are having with pointers> #include> using> namespace> std;> // A generic smart pointer class> template> <>class> T>>class> SmartPtr {> >T* ptr;>// Actual pointer> public>:> >// Constructor> >explicit> SmartPtr(T* p = NULL) { ptr = p; }> >// Destructor> >~SmartPtr() {>delete> (ptr); }> >// Overloading dereferencing operator> >T& operator*() {>return> *ptr; }> >// Overloading arrow operator so that> >// members of T can be accessed> >// like a pointer (useful if T represents> >// a class or struct or union type)> >T* operator->() {>return> ptr; }> };> int> main()> {> >SmartPtr<>int>>ptr(>new> int>());> >*ptr = 20;> >cout << *ptr;> >return> 0;> }> |
>
>Producción
20>
Nota: Los punteros inteligentes también son útiles en la gestión de recursos, como identificadores de archivos o sockets de red.
Tipos de punteros inteligentes
Las bibliotecas de C++ proporcionan implementaciones de punteros inteligentes en los siguientes tipos:
- auto_ptr
- único_ptr
- ptr_compartido
- débil_ptr
auto_ptr
Usando auto_ptr, puede administrar objetos obtenidos de nuevas expresiones y eliminarlos cuando se destruye auto_ptr. Cuando un objeto se describe a través de auto_ptr, almacena un puntero a un único objeto asignado.
Nota: Esta plantilla de clase está en desuso a partir de C++11. Unique_ptr es una nueva instalación con una funcionalidad similar, pero con seguridad mejorada.
único_ptr
único_ptr almacena un solo puntero. Podemos asignar un objeto diferente eliminando el objeto actual del puntero.
Ejemplo:
C++
// C++ program to demonstrate the working of unique_ptr> // Here we are showing the unique_pointer is pointing to P1.> // But, then we remove P1 and assign P2 so the pointer now> // points to P2.> #include> using> namespace> std;> // Dynamic Memory management library> #include> class> Rectangle {> >int> length;> >int> breadth;> public>:> >Rectangle(>int> l,>int> b)> >{> >length = l;> >breadth = b;> >}> >int> area() {>return> length * breadth; }> };> int> main()> {> // --/ Smart Pointer> >unique_ptr P1(>new> Rectangle(10, 5));> >cout // This'll print 50 // unique_ptr P2(P1); unique_ptr P2; P2 = move(P1); // This'll print 50 cout // cout return 0; }> |
>
>Producción
50 50>
ptr_compartido
Mediante el uso ptr_compartido más de un puntero puede apuntar a este objeto a la vez y mantendrá una Contador de referencia utilizando el usar_count() método.

C++
// C++ program to demonstrate the working of shared_ptr> // Here both smart pointer P1 and P2 are pointing to the> // object Addition to which they both maintain a reference> // of the object> #include> using> namespace> std;> // Dynamic Memory management library> #include> class> Rectangle {> >int> length;> >int> breadth;> public>:> >Rectangle(>int> l,>int> b)> >{> >length = l;> >breadth = b;> >}> >int> area() {>return> length * breadth; }> };> int> main()> {> >//---/ Smart Pointer> >shared_ptr P1(>new> Rectangle(10, 5));> >// This'll print 50> >cout shared_ptr P2; P2 = P1; // This'll print 50 cout // This'll now not give an error, cout // This'll also print 50 now // This'll print 2 as Reference Counter is 2 cout << P1.use_count() << endl; return 0; }> |
>
>Producción
50 50 50 2>
débil_ptr
Weak_ptr es un puntero inteligente que contiene una referencia no propietaria a un objeto. Es mucho más similar a share_ptr excepto que no mantendrá un Contador de referencia . En este caso, un puntero no tendrá un punto fuerte en el objeto. La razón es que si se supone que los punteros contienen el objeto y solicitan otros objetos, entonces pueden formar una Punto muerto.

C++
java largo a int
// C++ program to demonstrate the working of weak_ptr> // Here both smart pointer P1 and P2 are pointing to the> // object Addition to which they both does not maintain> // a reference of the object> #include> using> namespace> std;> // Dynamic Memory management library> #include> class> Rectangle {> >int> length;> >int> breadth;> public>:> >Rectangle(>int> l,>int> b)> >{> >length = l;> >breadth = b;> >}> >int> area() {>return> length * breadth; }> };> int> main()> {> >//---/ Smart Pointer> >shared_ptr P1(>new> Rectangle(10, 5));> > >// create weak ptr> >weak_ptr P2 (P1);> > >// This'll print 50> >cout // This'll print 1 as Reference Counter is 1 cout << P1.use_count() << endl; return 0; }> |
>
>Producción
50 1>
Las bibliotecas de C++ proporcionan implementaciones de punteros inteligentes en forma de auto_ptr, Unique_ptr, Shared_ptr y débil_ptr.