[C con Clase] En relación a Shared_Ptr y memory leaks

Miguel Ángel Torres Fernández-Píñar miguelangeltorresfp en gmail.com
Lun Dic 30 08:34:41 CET 2013


Buenos días Steven.

Más o menos entiendo la idea. Lo que me cuesta ahora es saberlo aplicar en
la práctica.

Y me doy cuenta de que lo que me falta es la base.

No tengo claro cuándo debo definir atributos ( miembros de una clase ) como
punteros a objetos ( en este caso con Shared_Ptr ) o como variables de
objetos.

Si los atributos son definidos como variables de objetos, aunque no lo haga
yo explicitamente, la clase los crea en el constructor, no ???

Y si son definidos como punteros, entonces puedo crearlos yo cuando y donde
quiera, no ???

Y no entendí esto :

Siempre nos interesa construir el puntero compartido; así que haz esto:

shared_ptr<int> sp = new int;

¿ Con tipos básicos como int también se debe de usar Shared_Ptr ???, es
decir, usar punteros ???.
Porque yo estoy usando constantemente variables de tipo int como atributos
de las diferentes clases que creo. Es decir, no los creo con "new".

Y supongo que en tal caso sería así, no ???
shared_ptr<int> sp = <shared_ptr>( new int);

En fin, Steven, no te preocupes mucho, supongo que necesito tiempo para
irme aclarando con todo esto.

Saludos !!!



El 29 de diciembre de 2013, 19:20, Miguel Ángel Torres Fernández-Píñar <
miguelangeltorresfp en gmail.com> escribió:

> Muchas gracias Steven.
>
> Voy a tratar de asimilarlo con calma.
>
> Como siempre una gran explicación.
>
> Muchísimas gracias una vez más por tu dedicarnos tu valioso tiempo.
>
>
> El 29 de diciembre de 2013, 18:30, Davidson, Steven <srd4121 en njit.edu>escribió:
>
>> Hola Miguel Ángel,
>>
>> 2013/12/29 Miguel Ángel Torres Fernández-Píñar <
>> miguelangeltorresfp en gmail.com>
>>
>>> Buenos días a todos.
>>>
>>> Me han recomendado usar mejor punteros inteligentes ( Shared_Ptr ) para
>>> miembros de una clase, para evitar memory leaks, sobre todo en casos en el
>>> que tenga que cargar imágenes, textos, etc..
>>>
>>> Me dicen además que de esta forma puedo crear estos objetos en el
>>> momento en el que me convenga. Que no se tienen que crear cuando instancio
>>> un objeto de la clase.
>>>
>>> Me comentan que debo evitar crear objetos con el operador "new".
>>>
>>> Pero sigo sin tener todo esto muy claro.
>>>
>>>
>> La idea es reducir la posibilidad de cometer errores durante la
>> programación. El problema de usar memoria dinámicamente adjudicada es que
>> tienes que liberarla. Si uno no tiene cuidado, o simplemente no tiene
>> control acerca del momento de perder esa dirección de memoria, entonces
>> perdemos la oportunidad de liberar esa memoria. A esto lo llamamos "fuga de
>> memoria" (o en inglés, memory leak).
>>
>> Existen varias clases-plantilla, que principalmente son: 'shared_ptr',
>> 'unique_ptr' (previamente, 'auto_ptr'), y 'weak_ptr' que sirven para
>> representar punteros agregando algún "grado" de seguridad. Con esto,
>> podemos crear un sistema de gestión de memoria que posiblemente tenga una
>> "recogida de basura" (en inglés, garbage collection), que alivia el
>> problema y peligro de las fugas de memoria, automatizando la liberación de
>> memoria previamente adjudicada dinámicamente. Por ello, a estas
>> clases-plantilla se llaman "punteros inteligentes".
>>
>> El caso de 'shared_ptr' sirve para compartir una misma dirección de
>> memoria dinámicamente adjudicada entre varios objetos. Eso sí, la
>> liberación de tal memoria recae en cada objeto; típicamente, el destructor
>> por defecto liberará la memoria, pero sólo cuando sea el último y no
>> comparta con otros objetos. Dicho esto, 'shared_ptr' actúa más como el
>> patrón de la fábrica, compartiendo la misma dirección de memoria, pero
>> tomando nota de la cuenta de objetos que la comparten. Cuando la cuenta sea
>> 0 (cero), y por tanto no haya dueños de tal dirección de memoria, entonces
>> se libera tal memoria.
>>
>> Por ejemplo, si tengo un miembro de tipo "string", ¿ debería  de usar
>>> "Shared_Ptr<string>" ???
>>>
>>>
>> No, porque el miembro es un objeto de la clase 'string', no un puntero a
>> 'string'. Si tuvieras esto:
>>
>> class Nombre
>> {
>> private:
>>   string *pNombre;
>>
>>   Nombre( const string &nom )
>>   {
>>     pNombre = new string( nom );
>>   }
>>   ~Nombre()  { delete pNombre; }
>> };
>>
>> Entonces sí podrías usar 'shared_ptr<string>'; esto es,
>>
>> class Nombre
>> {
>> private:
>>   shared_ptr<string> spNombre;
>>
>>   Nombre( const string &nom )
>>   {
>>     spNombre = make_shared<string>( new string( nom ) );
>>   }
>> };
>>
>> Siempre nos interesa construir el puntero compartido; así que haz esto:
>>
>> shared_ptr<int> sp = new int;
>>
>> Si no, entonces usa 'make_shared' para seguir esta práctica.
>>
>> Y en el caso de un vector de objetos de tipo "X", o de un vector " que
>>> contiene otro vector de objetos de tipo "X" ?
>>>
>>>
>> Es el mismo ejemplo anterior, si no escribes objetos dinámicamente
>> adjudicados, entonces no necesitas punteros y por tanto no necesitas
>> punteros inteligentes. Ciertamente, la clase-plantilla 'vector' sí usa
>> memoria dinámica, pero eso no es tu problema, sino el de 'vector'. Por
>> ejemplo,
>>
>> vector< vector<int> > vvi;
>>
>> vvi.push_back( vector<int>(100) );  // Crea un vector que reserva 100
>> enteros y agrégalo a 'vvi'.
>>
>> Ahora bien, si se trata de un vector de vectores dinámicos, entonces sí
>> usaríamos un puntero inteligente; por ejemplo,
>>
>> vector< unique_ptr< vector<int> > > vpvi;
>>
>>
>> Espero que esto te aclare las dudas.
>>
>> Steven
>>
>>
>> _______________________________________________
>> Lista de correo Cconclase Cconclase en listas.conclase.net
>> http://listas.conclase.net/mailman/listinfo/cconclase_listas.conclase.net
>> Bajas: http://listas.conclase.net/index.php?gid=2&mnu=FAQ
>>
>
>
------------ próxima parte ------------
Se ha borrado un adjunto en formato HTML...
URL: <http://listas.conclase.net/pipermail/cconclase_listas.conclase.net/attachments/20131230/bb2f2296/attachment.html>


Más información sobre la lista de distribución Cconclase