none
Asignación de variables por referencia - null

    Question

  • Buenas tardes, tengo una pregunta un poco tonta, yo estoy claro en que los objetos se pasan por referencia aun en las instancias pero si le asigno null a uno el otro no deberia tener ya el null?

    Ej.:

    Object aaa = new Object();

    Object bbb = aaa ;

    aaa = null;

    GC.Collect();

     

    Se que el codigo anterior no tiene mucho sentido pero ilustra perfectamente mi duda. El objeto bbb no seberia tener asignado null??? (si es asi no se que pasa pero no es ese el comportamiento que tiene)

    Thursday, March 10, 2011 3:16 PM

Answers

  • Madre mía que cacao, a ver si nos aclaramos, cojo el código original:

    Object aaa = new Object();
    Object bbb = aaa ;
    
    aaa = null;
    

    La primera línea crea una variable y un nuevo objeto. Por debajo en .NET se crean dos cosas:

    1) El objeto en el heap (un trozo de memoria donde estará el objeto). Esto es la parte del "new Object()"

    2) Una variable en la pila de ejecución del hilo actual. Esta variable es una referencia que apunta al trozo de memoria que se creó en 1. Esto es la parte de "Object aaa"

    Luego en la segunda línea se crea una nueva variable ("Object bbb"), y se hace que apunte al trozo de memoria del heap que creamos en la línea anterior con el new.

    En la tercera línea se utiliza una variable existente (aaa) y se le hace apuntar a otro sitio (null). bbb obviamente sigue apuntando al trozo de memoria que se creo en la primera línea.

    En cambio en el código de Cruznick.

    ClaseA a = new ClaseA();
    ClaseA aa = new ClaseA();
       
    aa = a;
    a.A1 = 2;

    En la primera línea se reserva un trozo de memoria para un objeto del tipo ClaseA en el heap y se crear una variable a en la pila que apunta a ese trozo de memoria (que vamos a llamar trozo 1).

    En la segunda línea se reserva otro trozo de memoria para un objeto del tipo ClaseA en el heap y se crear una variable aa en la pila que apunta a ese trozo de memoria (que vamos a llamar trozo 2).

    En la tercera línea se hace que aa apunte al mismo sitio que apunta a. Es decir aa en vez de apuntar a trozo 2, ahora apunta a trozo 1. Como nadie apunta ya a trozo 2 el Garbage Collector en un futuro cercano lo liberará.

    En la última línea, se utiliza la variable a para cambiar un valor del objeto de tipo ClaseA. Es decir, se utiliza a, se va al trozo 1 de memoria, y se cambia algo allí. Por eso aa también "ve" el cambio, porque los dos apuntan al mismo trozo de memoria.

    A ver si así queda un poco más claro...

     


    Vicente Cartas Espinel - MVP XNA/DirectX

    Twitter - VicenteCartas

    Blog about C# and XNA Development

    Blog about Role Playing Games

    Thursday, March 10, 2011 5:33 PM
  • Creo que el caso esta en el lugar que asigna el valor null al objeto, en lugar de

    Object aaa = new Object();
    
    Object bbb = aaa ;
    
    aaa = null;
    
    GC.Collect();

     deberia invertir el orden, ejemplo

    Object aaa = new Object();
    
    aaa = null;
    
    Object bbb = aaa ;
    
    GC.Collect();
    
    

    Recuerda que el codigo se compila y se ejecuta en un orden secuencial, linea 1, linea 2, linea 3, y asi susecivamente hasta encontral alguna llamada a algun metodo, en tal caso pasa el control a dicho metodo, compilando y ejecutando  en su orden, linea 1, linea 2, y asi sucesivamente hasta encontral el final de dicho metodo y retornando al metodo o rutina original y continuando en el orden linea 4

     


    Angel R. Jimenez G.
    Software Development
    Santo Domingo
    Republica Dominicana
    Thursday, March 10, 2011 7:25 PM

All replies

  • hola

    si asi deberia ser, pero como compruebas si bbb es null o no ?

    Object aaa = new Object();

    Object bbb = aaa;

    aaa = null;

    if(bbb == null){

       Label1.Text = "bbb es null";

    }

    como se comporta este codigo ?

     

    saludos


    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina
    Thursday, March 10, 2011 3:22 PM
  • Lo compruebo debugueando y al final en la ultima linea bbb no es null por eso surgue mi duda porque hasta donde sabia las clases siempre son por referencia y los strucs por valor.
    Thursday, March 10, 2011 3:31 PM
  • Buenas tardes, tengo una pregunta un poco tonta, yo estoy claro en que los objetos se pasan por referencia aun en las instancias pero si le asigno null a uno el otro no deberia tener ya el null?

    Ej.:

    Object aaa = new Object();

    Object bbb = aaa ;

    aaa = null;

    GC.Collect();

     

    Se que el codigo anterior no tiene mucho sentido pero ilustra perfectamente mi duda. El objeto bbb no seberia tener asignado null??? (si es asi no se que pasa pero no es ese el comportamiento que tiene)

    Hola amigo... es así como dices el objeto bbb debería ser null, pero no entiendo esta parte "si es asi no se que pasa pero no es ese el comportamiento que tiene" Que comportamiento tiene?¿Que deseabas lograr y que obtuviste? Como verificaste que el objeto no es null? (aunque debería serlo). Saludos

    * Si pudieras mostrar el código en cuestión seria muy útil

    Thursday, March 10, 2011 3:37 PM
  • Hola, gracias por la ayuda:

     

    El objeto bbb sigue siendo un object (su valor) en vez de null, lo verifico debugueando la aplicacion paso a paso y despues de la asignación del null noto que bbb sigue con su valor original.

    Thursday, March 10, 2011 3:41 PM
  • Lo compruebo debugueando y al final en la ultima linea bbb no es null por eso surgue mi duda porque hasta donde sabia las clases siempre son por referencia y los strucs por valor.

    como lo compruebas mediante debug? Podrías poner el fragmento de código en cuestión? 

     

     

    Thursday, March 10, 2011 3:41 PM
  • Hola, ya realice la prueba y efectivamente sucede lo que indica el compañero Prueba123, ¿pero no es esto lo que deberia pasar? es decir la instancia b toma el valor object en la linea anterior.. (Object b = a;) siendo a = object... creo que aqui se aplica algo de encapsulamiento, pues el alterar al objeto a.. no afecta a la instancia b... pues este objeto ya tiene defiinido sus prpiedades, para que este sea null seria necesaerio reasignarlo:

    Object a = new Object();
    Object b;
    a = null;
    b = a;
    if (b == null)
    {
     MessageBox.Show("SI ES NULL B");
    }  


    Nicolás Herrera
    Bogotá - Colombia
    "Daría todo lo que sé, por la mitad de lo que ignoro." Rene Descartes
    Thursday, March 10, 2011 3:55 PM
  • Hola, ya realice la prueba y efectivamente sucede lo que indica el compañero Prueba123, ¿pero no es esto lo que deberia pasar? es decir la instancia b toma el valor object en la linea anterior.. (Object b = a;) siendo a = object... creo que aqui se aplica algo de encapsulamiento, pues el alterar al objeto a.. no afecta a la instancia b... pues este objeto ya tiene defiinido sus prpiedades, para que este sea null seria necesaerio reasignarlo:

    Object a = new Object();
    Object b;
    a = null;
    b = a;
    if (b == null)
    {
     MessageBox.Show("SI ES NULL B");
    }  


    Nicolás Herrera
    Bogotá - Colombia
    "Daría todo lo que sé, por la mitad de lo que ignoro." Rene Descartes

    Para el objeto b se le esta asignando a por referencia (es decir b hace referencia al objeto a) por lo que cuando el objeto a cambie el objeto b tambien deberia hacerlo y es algo que puedes comprobar cambiando alguna propiedad del objeto a hay mismo el objeto b la tiene pero en el caso particular de que se le asigna null al objeto a no ocurre lo mismo para el objeto b
    Thursday, March 10, 2011 4:00 PM
  • Lo compruebo debugueando y al final en la ultima linea bbb no es null por eso surgue mi duda porque hasta donde sabia las clases siempre son por referencia y los strucs por valor.

    como lo compruebas mediante debug? Podrías poner el fragmento de código en cuestión? 

     

     


    Si mediante debug, en este momento no lo tengo a la mano pero con el ejemplo simple que puse sucede lo mismo tal cual.
    Thursday, March 10, 2011 4:05 PM
  • Hola nico

    Por algún motivo ocurre de esta forma, pero yo he intentado hacer copias de un objeto de tipo digamos A que contiene unas listas etc... y después modifico los valores en las listas del objeto copiado y se modifican los valores en el objeto principal... ahora me fije, si antes de asignar el objeto a a b, se asigna null a a, pues ahí si b pasa a ser null.. Así que adapte un pequeñito ejemplo:

     ClaseA a = new ClaseA();
          ClaseA aa = new ClaseA();
          
          aa = a;
          a.A1 = 2;
          
          if (aa.A1==2)
          {
            textBox2.Text = "se cambio el valor por referencia";
          }
    
    y en este caso, se cambia el valor... Aclaro que ClaseA tiene un atributo entero y en el constructor lo inicializo a 1....

     

     

     

     

    Thursday, March 10, 2011 4:12 PM
  • Hola Cruznick, pero estas apuntando los dos objetos al mismo atributo, es decir, no se cambio por referencia... si no que cambiaste el valor del atributo con un objeto (a), y luego  apuntaste el objeto (aa) al atributo ya modificado...  Hasta donde se solo se modifican valores por referencia con la palabra reservada (ref) en los metodos de las clases.

    Atento a los comentarios y criticas constructivas, saludos


    Nicolás Herrera
    Bogotá - Colombia
    "Daría todo lo que sé, por la mitad de lo que ignoro." Rene Descartes
    Thursday, March 10, 2011 4:25 PM
  • mmmmm, nico aa y a son los objetos, asigno aa=a y después hago a.A1=2 con eso se modifico el valor de aa.A1 
    Thursday, March 10, 2011 4:49 PM
  • Hola Cruznick, no quiero caer en el error de la terquedad ni la arrogancia (todos estamos aqui para aprender), asi que agradezco que me corrijas si me equivoco:

    A1 es un atributo entero de tu case (ClaseA), instancas dos objetos (a) y (aa) de esta clase (ClaseA)... luego el objeto (a) modifica el valor del atributo (a.A1 = 2)... entonces el atributo(A1) de tu clase (ClaseA) tiene el valor entero 2... luego el objeto (aa) simplemente apunta al atrubuto que ya tiene un valor entero (2)... (aa.A1) es decir la asignacion (aa == a) no esta haciendo nada respecto a modificar su valor, podrias hacer la prueba sin esta linea y comprobarlo... (lo voy a hacer en mi hora del almuerzo jajaja poruque estoy atareado en el trabajo :-( ).

    Atento a tu respuesta, resultado y demas sugerencias, saludos 


    Nicolás Herrera
    Bogotá - Colombia
    "Daría todo lo que sé, por la mitad de lo que ignoro." Rene Descartes
    Thursday, March 10, 2011 5:15 PM
  • hola

    lo has intentado con algun otro objeto que no se Object ?

    List<string> aaa = new List<string>();

    List<string> bbb = aaa;

    aaa = null;

    if(bbb == null){

       Label1.Text = "bbb es null";

    }

    para ver si con asl listas genericas pasa lo mismo

    saludos


    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina
    Thursday, March 10, 2011 5:21 PM
  • hola

    lo has intentado con algun otro objeto que no se Object ?

    List<string> aaa = new List<string>();

    List<string> bbb = aaa;

    aaa = null;

    if(bbb == null){

       Label1.Text = "bbb es null";

    }

    para ver si con asl listas genericas pasa lo mismo

    saludos


    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina

    Realmente en mi caso con clases propias y entre sus atributos tienen listas tambien y efectivamente pasa lo mismo, alguna idea de porque sucede esto???
    Thursday, March 10, 2011 5:29 PM
  • Madre mía que cacao, a ver si nos aclaramos, cojo el código original:

    Object aaa = new Object();
    Object bbb = aaa ;
    
    aaa = null;
    

    La primera línea crea una variable y un nuevo objeto. Por debajo en .NET se crean dos cosas:

    1) El objeto en el heap (un trozo de memoria donde estará el objeto). Esto es la parte del "new Object()"

    2) Una variable en la pila de ejecución del hilo actual. Esta variable es una referencia que apunta al trozo de memoria que se creó en 1. Esto es la parte de "Object aaa"

    Luego en la segunda línea se crea una nueva variable ("Object bbb"), y se hace que apunte al trozo de memoria del heap que creamos en la línea anterior con el new.

    En la tercera línea se utiliza una variable existente (aaa) y se le hace apuntar a otro sitio (null). bbb obviamente sigue apuntando al trozo de memoria que se creo en la primera línea.

    En cambio en el código de Cruznick.

    ClaseA a = new ClaseA();
    ClaseA aa = new ClaseA();
       
    aa = a;
    a.A1 = 2;

    En la primera línea se reserva un trozo de memoria para un objeto del tipo ClaseA en el heap y se crear una variable a en la pila que apunta a ese trozo de memoria (que vamos a llamar trozo 1).

    En la segunda línea se reserva otro trozo de memoria para un objeto del tipo ClaseA en el heap y se crear una variable aa en la pila que apunta a ese trozo de memoria (que vamos a llamar trozo 2).

    En la tercera línea se hace que aa apunte al mismo sitio que apunta a. Es decir aa en vez de apuntar a trozo 2, ahora apunta a trozo 1. Como nadie apunta ya a trozo 2 el Garbage Collector en un futuro cercano lo liberará.

    En la última línea, se utiliza la variable a para cambiar un valor del objeto de tipo ClaseA. Es decir, se utiliza a, se va al trozo 1 de memoria, y se cambia algo allí. Por eso aa también "ve" el cambio, porque los dos apuntan al mismo trozo de memoria.

    A ver si así queda un poco más claro...

     


    Vicente Cartas Espinel - MVP XNA/DirectX

    Twitter - VicenteCartas

    Blog about C# and XNA Development

    Blog about Role Playing Games

    Thursday, March 10, 2011 5:33 PM
  • Discúlpame amigo Nico, en ningún momento imagine que por intentar aclarar una duda o un error, y que en ningún momento dije que fuese suyo, fuéramos a caer en la terquedad o arrogancia, como bien usted dice, estamos para aprender y acá he aprendido mucho mas de lo que me hubiera imaginado... Mis disculpas si viste mis comentarios como un enfrentamiento a tu persona, nada mas lejos de mis intenciones... 

    Permitame nuevamente sin ánimos de ofender... si la linea que usted comenta que no hace nada es aa=a o sea que prescindir de ella arrojaría el mismo resultado, le comento que no es así, y esta vez lo he comprobado, la comente y comprobé en 2 textBox, uno para a.A1 y otro para aa.A1 los resultados fueron 2 y 1 respectivamente.... por lo que deduzco que no me explique bien( siempre ha sido mi problema :D muy pero muy malo para hacerme entender jejeje)... 

    Le reitero mis disculpas por el mal entendido, quizás tengo el concepto erroneo, me gustaría rectificarlo de ser así, para nada me molestaría que me indicara, usted o cualquiera, mis errores... 

         Saludos y mis respetos... atento a sus sugerencias

    Thursday, March 10, 2011 5:42 PM
  • Madre mía que cacao, a ver si nos aclaramos, cojo el código original:

     

    Object aaa = new Object();
    
    Object bbb = aaa ;
    
    
    
    aaa = null;
    
    

     

    La primera línea crea una variable y un nuevo objeto. Por debajo en .NET se crean dos cosas:

    1) El objeto en el heap (un trozo de memoria donde estará el objeto). Esto es la parte del "new Object()"

    2) Una variable en la pila de ejecución del hilo actual. Esta variable es una referencia que apunta al trozo de memoria que se creó en 1. Esto es la parte de "Object aaa"

    Luego en la segunda línea se crea una nueva variable ("Object bbb"), y se hace que apunte al trozo de memoria del heap que creamos en la línea anterior con el new.

    En la tercera línea se utiliza una variable existente (aaa) y se le hace apuntar a otro sitio (null). bbb obviamente sigue apuntando al trozo de memoria que se creo en la primera línea.

    En cambio en el código de Cruznick.

     

    ClaseA a = new ClaseA();
    
    ClaseA aa = new ClaseA();
    
      
    
    aa = a;
    
    a.A1 = 2;

     

    En la primera línea se reserva un trozo de memoria para un objeto del tipo ClaseA en el heap y se crear una variable a en la pila que apunta a ese trozo de memoria (que vamos a llamar trozo 1).

    En la segunda línea se reserva otro trozo de memoria para un objeto del tipo ClaseA en el heap y se crear una variable aa en la pila que apunta a ese trozo de memoria (que vamos a llamar trozo 2).

    En la tercera línea se hace que aa apunte al mismo sitio que apunta a. Es decir aa en vez de apuntar a trozo 2, ahora apunta a trozo 1. Como nadie apunta ya a trozo 2 el Garbage Collector en un futuro cercano lo liberará.

    En la última línea, se utiliza la variable a para cambiar un valor del objeto de tipo ClaseA. Es decir, se utiliza a, se va al trozo 1 de memoria, y se cambia algo allí. Por eso aa también "ve" el cambio, porque los dos apuntan al mismo trozo de memoria.

    A ver si así queda un poco más claro...

     


    Vicente Cartas Espinel - MVP XNA/DirectX

    Twitter - VicenteCartas

    Blog about C# and XNA Development

    Blog about Role Playing Games


    En base al código original, tendras algun link sobre alguna documentación oficial que sustente lo que dices??? (es que tengo una discucion con una persona que dice que si en una funcion yo voy a retornar el objeto bbb pero antes le asigne null al objeto aaa eso va a dar error en algun momento porque el recolector de basura va a eliminar la referencia de aaa y dice un monton de cuentos para marearme. El caso es que esa persona tiene un cargo de arquitecto de software y cree que siempre tiene la razon y me gustaria demostrarle que no es asi, gracias.)
    Thursday, March 10, 2011 6:17 PM
  • Hola Cruznick, tranquilo..... en ningun momento tome a mal tus palabras ni me parecieron ofensivas(por el contrario agradezco tiu paciencia con este loco obstinado)... (jajaja no se si sono feo lo que escribi en mi ultimo comentario)... lo de la terquedad y la arrogancia lo dije.. porque estaba seguro en un 80% de que tenias la razon (el otro 20 pensaba que yo tenia la razon)... pero yo obstinado en mi punto de vista no lo entendia (ahora con el aporte de Vicente me quedo mas claro)... Lamento el malentendido y fresco (expresion colombiana que indica tranquilo, relajate) no quiero dar la imagen de hombre iracundo en el foro :-) ;-).

    Saludos amigaso!!  


    Nicolás Herrera
    Bogotá - Colombia
    "Daría todo lo que sé, por la mitad de lo que ignoro." Rene Descartes
    Thursday, March 10, 2011 6:19 PM
  • Estoooo, prueba123, no se que responder realmente. La documentación oficial que dice eso existe, pero está de forma mucho más complicada y más detallada, y seguramente no está en un solo sitio.

    Aun así, un artículo en inglés que explica todo en mucho más detalle (con dibujitos y todo):

    http://www.c-sharpcorner.com/UploadFile/rmcochran/csharp_memory01122006130034PM/csharp_memory.aspx?ArticleID=9adb0e3c-b3f6-40b5-98b5-413b6d348b91

    Edit: si vas al final de la primera parte, hay un diagrama que muestra más o menos lo que estamos hablando, pero en general todo el artículo es MUY recomendable de leer.


    Vicente Cartas Espinel - MVP XNA/DirectX

    Twitter - VicenteCartas

    Blog about C# and XNA Development

    Blog about Role Playing Games

    Thursday, March 10, 2011 6:37 PM
  • No hay problema hermano nico, todo Bien, es bueno defender lo que creemos, así o rectificamos o ayudamos a otros a rectificar, el caso es que de todo se aprende, por eso me gusta este lugar....... Y mil Gracias a Vicente, presumo debe tener buenos dones de profesor ;-) 

    prueba123... creo que si le explicas a esa persona, de la forma que Vicente ha comentado, y conoce un poco del tema, no va a tener mucho mas que decirte... La explicación es la que Vicente te ha dejado por acá, otra cosa: sobre el GC te dejo un link: 

    http://social.msdn.microsoft.com/Forums/es-ES/vcses/thread/03b21eb6-5c43-4cea-91c2-adf4c79d5bbb

    donde me explican un poco estos temas, pero veras que : El Garbage Collector es el responsable de liberar memoria, eliminando todos aquellos objetos que están inaccesibles......

    Un objeto inaccesible es un objeto al cual NO apunta ninguna referencia, es decir un objeto al cual no se puede acceder de ninguna manera   

    o sea que mientras no se de la situación, el GC no va a eliminar el objeto.

    Saludos

    Thursday, March 10, 2011 6:38 PM
  • Gracias Cruznick :) La explicación que comentas de Eduard es muy clara sobre el GC.
    Vicente Cartas Espinel - MVP XNA/DirectX

    Twitter - VicenteCartas

    Blog about C# and XNA Development

    Blog about Role Playing Games

    Thursday, March 10, 2011 6:59 PM
  • Gracias Cruznick :) La explicación que comentas de Eduard es muy clara sobre el GC.
    Vicente Cartas Espinel - MVP XNA/DirectX

    Twitter - VicenteCartas

    Blog about C# and XNA Development

    Blog about Role Playing Games


    Gracias.
    Thursday, March 10, 2011 7:23 PM
  • No hay problema hermano nico, todo Bien, es bueno defender lo que creemos, así o rectificamos o ayudamos a otros a rectificar, el caso es que de todo se aprende, por eso me gusta este lugar....... Y mil Gracias a Vicente, presumo debe tener buenos dones de profesor ;-) 

    prueba123... creo que si le explicas a esa persona, de la forma que Vicente ha comentado, y conoce un poco del tema, no va a tener mucho mas que decirte... La explicación es la que Vicente te ha dejado por acá, otra cosa: sobre el GC te dejo un link: 

    http://social.msdn.microsoft.com/Forums/es-ES/vcses/thread/03b21eb6-5c43-4cea-91c2-adf4c79d5bbb

    donde me explican un poco estos temas, pero veras que : El Garbage Collector es el responsable de liberar memoria, eliminando todos aquellos objetos que están inaccesibles......

    Un objeto inaccesible es un objeto al cual NO apunta ninguna referencia, es decir un objeto al cual no se puede acceder de ninguna manera   

    o sea que mientras no se de la situación, el GC no va a eliminar el objeto.

    Saludos


    Gracias.
    Thursday, March 10, 2011 7:24 PM
  • Creo que el caso esta en el lugar que asigna el valor null al objeto, en lugar de

    Object aaa = new Object();
    
    Object bbb = aaa ;
    
    aaa = null;
    
    GC.Collect();

     deberia invertir el orden, ejemplo

    Object aaa = new Object();
    
    aaa = null;
    
    Object bbb = aaa ;
    
    GC.Collect();
    
    

    Recuerda que el codigo se compila y se ejecuta en un orden secuencial, linea 1, linea 2, linea 3, y asi susecivamente hasta encontral alguna llamada a algun metodo, en tal caso pasa el control a dicho metodo, compilando y ejecutando  en su orden, linea 1, linea 2, y asi sucesivamente hasta encontral el final de dicho metodo y retornando al metodo o rutina original y continuando en el orden linea 4

     


    Angel R. Jimenez G.
    Software Development
    Santo Domingo
    Republica Dominicana
    Thursday, March 10, 2011 7:25 PM