Punteros inteligentes en C++ (smart pointers) 2
By laparca
En el artículo anterior veíamos como crear una clase simple de puntero inteligente, pero no se mostró ningún ejemplo de su uso. Por este motivo, a continuación pasamos a poner un ejemplo y a ver las deficiencias de dicha clase:
Si hacemos la prueba, veremos como el destructor de UnaClase se llama automáticamente al término del programa. Con esto hemos conseguido nuestro primer objetivo, no tener que liberar nosotros mismos la memoria, pero ahora surgen otros problemas: ¿cómo utilizar el puntero en más partes de la aplicación que no sean el propio método?
Antes de continuar vamos a ver una cosita de C++ que nos ayudará mucho: el paso de parametros por referencia. Esto nos permite pasar a un método una referencia a un objeto y si lo modificamos estaremos modificando el objeto original. ¿Cómo se hace esto? pues muy fácil:
Como vemos, al poner los argumentos del método, justo después del tipo se ha añadido un símbolo &. Éste es el que indica que es por referencia. Si no se pone nada sería por valor y si se pusiera un * sería una dirección. De este modo, ya podríamos pasar sin peligro a un método un puntero inteligente:
Ahora imaginemos el siguiente caso:
Estamos haciendo uso de STL para el vector. Este código no funcionará, ya que la clase vector hace uso del constructor de copia de PtrSimple, que no lo hemos definido, por lo que utilizaría el contructor de copia por defecto. Esto derivaría en que en un momento dado el puntero podría liberarse mientras en el vector seguiría existiendo un puntero al mismo, lo que supondrá un fallo de segmentación. Para solventar esto, hay que hacer uso de contadores de uso de punteros, que nos permitirán saber cuantas copias hay del mismo para liberarlo en caso necesario:
Con la clase anterior, ya no debería haber problemas con el tema de STL ni de que hayan copias por ahí… ¿o no? Siguen existiendo casos conflictivos, por ejemplo, tener que pasar sólo la dirección (no el puntero) y luego desde otra parte del código tomar dicho puntero a una clase. Con este caso, perderiamos los contadores de uso que teníamos, por lo que perdemos el control.
A parte de lo anterior, también es constatable que nos faltan funcionalidades: y si quiero comparar dos puntero, y si quiero asignarle una dirección nueva al puntero cuando este ya tenía otra, etc. Esta y otras dudas, para el siguiente artículo.