Los punteros inteligentes (smart pointers) son objetos que se parecen y se comportan como los punteros tradicionales, pero son más inteligentes. ¿Qué significa esto? Para parecerse y comportarse como punteros, los punteros inteligentes necesitan tener el mismo interfaz que los punteros normales: necesitan soportar operaciones de derreferenciación (operador *) y de indirección (operador ->).
Un objeto que se parece y se comporta como otro se llama objeto proxy, o simplemente proxy. El patrón de diseño proxy y sus múltiples usos se describen en detalle en los libros Design Patterns: Elements of reusable object-oriented software y Pattern Oriented Software Architecture.
La inteligencia de los smart pointers reside en las capacidades extendidas que presentan frente a los punteros tradicionales. Probablemente los errores mas frecuentes en C++ (y C) son aquellos relacionados con el manejo de memoria y los punteros: fugas de memoria, fallos en la reserva de memoria, punteros que apuntan a zonas de memoria inválida y otras diversiones. Tener un puntero inteligente que se haga cargo de todas estas tareas de forma automática nos ahorra muchos dolores de cabeza.
El ejemplo más simple de puntero inteligente es auto_ptr, que viene incluido en la librería estándar de C++ (STL). Se puede encontrar en la cabecera <memory>. A continuación se muestra una parte de la implementación de auto_ptr, para ilustrar su funcionamiento:
1 2 3 4 5 6 7 8 9 10 | template <class T> class auto_ptr { T* ptr; public: explicit auto_ptr(T* p = 0) : ptr(p) {} ~auto_ptr() {delete ptr;} T& operator*() {return *ptr;} T* operator->() {return ptr;} // ... }; |
Como se puede observar, auto_ptr es una simple envoltura alrededor de un puntero tradicional que delega todas las operaciones relevantes a su puntero interno (derreferencia e indirección). Su inteligencia se encuentra en el destructor: el destructor se encarga de eliminar la memoria del puntero.
Para el usuario de auto_ptr, esto significa que en lugar de escribir:
1 2 3 4 5 | void foo() { MyClass* p(new MyClass); p->DoSomething(); delete p; } |
Simplemente puede escribir:
1 2 3 4 | void foo() { auto_ptr<MyClass> p(new MyClass); p->DoSomething(); } |
Y auto_ptr nos garantiza que la memoria se liberará automáticamente cuando el objeto p salga de su ámbito.
Artículos de esta serie:
- Smart pointers en C++: ¿Qué son? (parte 1 de 3)
- Smart pointers en C++: ¿Por qué debería usarlos? (parte 2 de 3)
- Smart pointers en C++: ¿Qué tipo de smart pointer emplear? (parte 3 de 3) [próximamente]
