Inicio > Informática > Pointer Ownership

Pointer Ownership


No sé muy bien como traducir el término “pointer ownership”. Si bien, en un lenguaje de programación con punteros como C++, éste se refiere a quién pertenece el puntero. Es un tema que me chirría bastante, porque no hay una convención universal, lo que provoca que cada clase o función tenga la suya propia y, si no está especificada en la documentación, o bien no leemos esta última (que es lo que suele pasar), terminamos con memory leaks, fallos de segmentación y otras lindeces.

En Stack Overflow (¡qué gran página!) tienen una discusión muy interesante sobre el tema, en la que se habla de que una buena convención, también recogida en el libro de Scott Meyers, Effective C++: el objeto que reserva memoria (malloc, new), es el que debe tener la pertenencia del objeto. Si la pertenencia es compartida, usar boost::shared_ptr

Lo ideal es que cuando una función devuelve un objeto, debe devolver una copia, o bien una referencia const. En el caso de pasar un objeto a una función, éste debe ser copiado. El problema es que en C++ tenemos que conocer el tipo dinámico del objeto en tiempo de compilación para poder realizar la copia, así que debemos implementar el método clone si estamos usando una clase polimórfica, para que actúe el polimorfismo y se llame al constructor adecuado.

La siguiente interfaz facilita un poco las cosas. Para hacer una jerarquía de clases “clonable” habría que hacer que la clase Base herede de Cloneable<Base>, y que las subclases redefinan el método clone.


template <class T>
class Cloneable {
public:
         virtual ~Cloneable(){}
         virtual T* clone() = 0;
}

class Base : public Cloneable {
public:
         Base* clone() {
                  return new Base(*this);
         }
}

class Derived : public Base {
public:
         Derived* clone() {
                  return new Derived(*this);
         }
}

Es una manera de hacerlo, aunque tiene un inconveniente: puede que al programador se le olvide redefinir el método clone. Podemos solucionarlo comprobando en el método clone si la clase dinámica es igual a la del método llamado o, en caso contrario, lanzar una excepción.


Derived* clone() {
         Derived* clon = new Derived(*this);
         assert(typeid(*clon) == typeid(*this));
         return clon;
}

Hay un capítulo muy extenso sobre clonación en el libro de Andrei Alexandrescu, Modern C++ Design. Sin duda, uno de los mejores libros para aprender c++ avanzado.

Desde luego es un fastidio el tener que usar punteros para poder utilizar polimorfismo. Afortunadamente, hay librerías para facilitarnos la vida a los programadores. Si tenemos un objeto que debe mantener una lista de objetos de clases polimórficas, una manera de evitarlos olvidos a la hora de liberar memoria, es usar los contenedores de punteros de boost , porque nunca debemos usar contenedores estándar con smart pointers (más en la documentación de boost)

Conclusión

  • La pertenencia de un puntero debe ser del objeto que lo crea
  • En caso de pertenencia compartida, usar boost::shared_ptr
  • Si una función devuelve un puntero, debe ser una copia, o bien una referencia const
  • Para almacenar punteros sin preocupaciones sobre memoria, utilizar boost::ptr_containter
Categorías:Informática Etiquetas: , ,
  1. Aún no hay comentarios.
  1. No trackbacks yet.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s