Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





Cosa De C++

Iniciado por Pogacha, 17 de Noviembre de 2005, 12:45:16 AM

« anterior - próximo »

Pogacha

 Seguid el ejemplo:
class TCosa
{
   TObjetoInterno *OI;

public:

  TCosa(const TObjetoInterno *o = NULL);
  ~TCosa();

  TCosa  operator+(const TCosa &c) const;

  TObjetoInterno *Tomar_ObjetoInterno() const;
};


TObjetoInterno *TCosa::Tomar_ObjetoInterno() const
{
  return OI;
}


TCosa::TCosa(const TObjetoInterno *o)
{
  OI = o;  // es un mal diseño, pero supongamos para que valga el ejemplo
}

TCosa::~TCosa()
{
 if(OI)  delete OI;
}

TCosa TCosa::operator+(const TCosa &c) const
{
  TObjetoInterno *NO = new TObjetoInterno;

  NO->FuncionSuma(OI, c.OI);

  return TCosa(NO);  // Esto es lo que no anda :( , me destruye el objeto antes de pasarlo
}


void main(void)
{
  TCosa a(new TObjetoInterno);
  TCosa b(new TObjetoInterno);
  TCosa c;

  c=a+b;             // esto es lo que no me funciona ...
  c->Tomar_ObjetoInterno()->FuncionHola();    // me termina dando error de proteccion de memoria

}


Como hago para que esto funcione ?
O sea devolver un objeto en una función y que no lo destruya antes?
Nesesito esta funcionalidad ...

Saludos.

ProD

 Buenas, ¿Has probado a tener un constructor copia?, quizás te interesaría también tener un
operador de asignación. Saludos
as ideas son capitales que sólo ganan intereses entre las manos del talento

zupervaca

 
Citarreturn TCosa(NO);  // Esto es lo que no anda :( , me destruye el objeto antes de pasarlo
el objeto NO no te lo puede destruir ya que lo has creado con new y el objeto TCosa lo esta devolviendo y el lenguaje no lo puede destruir con lo que el fallo no puede estar ahi

por ejemplo yo tengo esto en mi clase vector3
  __forceinline Vector3 Vector3::operator+ ( Vector3 &v )
  {
   return Vector3( x+v.x, y+v.y, z+v.z );
  }

CoLSoN2

 Normal que te pete.

Lo que ocurre es,

En operator+:
- Se crea un objeto dinámico "NO". Para que se borre deberías hacerlo manualmente usando delete.
- Luego creas un objeto estático en el return, y asignas "NO" a él. Este objeto sí será borrado después de _copiarse_ a la variable "c" (en la línea c = a+b;). Al copiarse, el TObjetoInterno* "NO" se comparte entre ambos, porque se igualan los valores de esa variable, que es un puntero.
- Al borrarse la variable estática que se creó en el return, se libera la memoria de "NO" (en ~TCosa()), por lo que el TObjetoInterno* de la variable "c" deja de apuntar a un bloque de memoria válido.

Solución

Sobrecarga el operador de asignación para TCosa y "clona" el miembro "OI" de la clase. Algo como:


TCosa& TCosa::operator=(const TCosa& obj)
{
this.IO = new TObjetoInterno;

// igualar this.IO a obj.IO, aunque lo suyo sería usar un constructor copia
this.IO->miembro = obj->IO->miembro;

return *this;

}


Normalmente, si una clase tiene miembros que son objetos dinámicos (reservas su memoria usando new) querrás sobrecargar el operador de asignación, para que al igualar un objeto de esa clase a otro este objeto no se comparta (si lo cambias o borras en uno de sus padres, también se altera en el otro), sino que se tengan instancias iguales pero independientes.
Manuel F. Lara
Descargar juegos indie  - blog sobre juegos indie y casual
El Desarrollo Personal.com  - blog sobre productividad, motivación y espíritu emprendedor

zupervaca

 
CitarOI = o;  // es un mal diseño, pero supongamos para que valga el ejemplo
se supone que el operador = lo tiene como indicas

editado: a pues no, por que tendria que poner el *

CoLSoN2

 Si con OI = o lo que realmente está haciendo es clonar el objeto (crear una nueva instancia y copiar los datos del otro), entonces valdría con cambiar
TCosa c;
c = a+b;

por
TCosa c((a+b).OI);
Manuel F. Lara
Descargar juegos indie  - blog sobre juegos indie y casual
El Desarrollo Personal.com  - blog sobre productividad, motivación y espíritu emprendedor

zupervaca

 nos viene ni que pintado este post para otro tema un poco off-topic y es sobre las optimizaciones del compilador, por ejemplo, si en vez de hace esto:

TCosa c;
c=a+b;

hacemos esto

TCosa c=a+b;

¿el objeto creado en el "return TCosa(NO);" se aprovecha o se crea c y otro mas y luego se llama al operador = ? yo creo que en principio optimizaria haciendo que c sea TCosa(NO), pero tampoco lo he mirado nunca, ¿que pensais? ¿o llama al operador = por si se hacen mas cosas?

editado: partiendo de que el operador = de la clase sea el de por defecto sin redifinir

CoLSoN2

 Yo diría que en ningún caso c se "convierte" en el objeto TCosa(NO), siempre se crea y se destruye un objeto estático temporal.
Manuel F. Lara
Descargar juegos indie  - blog sobre juegos indie y casual
El Desarrollo Personal.com  - blog sobre productividad, motivación y espíritu emprendedor

zupervaca

 ya, en este codigo es asi, pero si el operador = no estuviera redefinido y estuviera el de por defecto del compilador ¿que ocurriria, optimiza o lo hace como si hubieramos redifinido el operador =?

ethernet

 A mi el código no me compila.

Bastaría con poner :


TCosa c=a+b;


y todo funcionaría a la perfección y además es lo más óptimo. En tu caso pasa lo que dice Colson. Recomiendo mirar effective c++ para cosas de ese tipo, hay ejemplos de casi todo eso.


CoLSoN2

Cita de: "ethernet"A mi el código no me compila.

Bastaría con poner :


TCosa c=a+b;


y todo funcionaría a la perfección y además es lo más óptimo. En tu caso pasa lo que dice Colson.
Si pasa lo que digo yo, ¿por qué no pasa lo mismo en este caso?
Manuel F. Lara
Descargar juegos indie  - blog sobre juegos indie y casual
El Desarrollo Personal.com  - blog sobre productividad, motivación y espíritu emprendedor

zupervaca

 entonces si de esta manera funciona "TCosa c=a+b;" comprobamos de que el compilador si optimizaria y no llama al operador = ya que el return TCosa(NO) se convierte en c y el objeto NO no es destruido ya que el objeto devuelto por la funcion no es destruido y no se llama al destructor

ethernet

Cita de: "CoLSoN2"Si pasa lo que digo yo, ¿por qué no pasa lo mismo en este caso?
Pues porque en este caso se contruye el objeto una sola vez.  

Pogacha

 
Cita de: "zupervaca"por ejemplo yo tengo esto en mi clase vector3
  __forceinline Vector3 Vector3::operator+ ( Vector3 &v )
  {
   return Vector3( x+v.x, y+v.y, z+v.z );
  }
Es claro, eso me andaba al galope, tenia años usandolo, pero cuando quize hacer una clase auxiliar para manejo de texto terminé con este problema ...

El operador copia seria "TCosa& TCosa::operator=(const TCosa& obj);"?

Gracias a todos

Edit :

Recien estoy callendo:

Hasta a+b tengo todo bien, pero cuando paso por el = al no tener un operador copia, el compilador hace una copia de memoria (que seria la copia por defecto) del objeto a+b al c, luego destruye el a+b por que se descarta y ahí pierdo el ObjetoInterno de c ...
OK !!!!
(ole)  (ole)  (ole)
Que bueno que lo entendí !!!!
Estoy re contento, en realidad este problema me venia persiguiendo desde hace años y recién ahora logro agarrarlo ... !!!

Saludos y gracias nuevamente

Edit2:

Para que no digan que estoy loco, releí de nuevo y esto me lo decía colson claramente, aun que no le entendí en la primera lectura ...
CitarEn operator+:
- Se crea un objeto dinámico "NO". Para que se borre deberías hacerlo manualmente usando delete.
- Luego creas un objeto estático en el return, y asignas "NO" a él. Este objeto sí será borrado después de _copiarse_ a la variable "c" (en la línea c = a+b;). Al copiarse, el TObjetoInterno* "NO" se comparte entre ambos, porque se igualan los valores de esa variable, que es un puntero.
- Al borrarse la variable estática que se creó en el return, se libera la memoria de "NO" (en ~TCosa()), por lo que el TObjetoInterno* de la variable "c" deja de apuntar a un bloque de memoria válido.

Saludos y gracias por triplicado

Yoshi.css

 
CitarHasta a+b tengo todo bien, pero cuando paso por el = al no tener un operador copia, el compilador hace una copia de memoria (que seria la copia por defecto) del objeto a+b al c, luego destruye el a+b por que se descarta y ahí pierdo el ObjetoInterno de c ...
OK !!!!
Y no solo eso. Si realizas la asignación (=) entre dos objetos, y no tienes definido el constructor de copia, el compilador realiza una copia de un objeto en otro bit a bit. El problema surge cuando trabajas con punteros dentro de la clase, y es que ambos objetos estarían accediendo a la mísma dirección de memoria, lo que supone un problema grave y no deseado.






Stratos es un servicio gratuito, cuyos costes se cubren en parte con la publicidad.
Por favor, desactiva el bloqueador de anuncios en esta web para ayudar a que siga adelante.
Muchísimas gracias.