Título: Uso de referencias con memoria dinámica [C++] Publicado por: K-YreX en 30 Marzo 2019, 14:23 pm Cuando trabajamos con memoria dinámica y pasamos una variable (ya sea un array, una variable sencilla o un objeto), hasta el punto que yo sé, lo que estamos pasando es el puntero que apunta a la dirección de memoria donde hemos guardado esa variable. Entonces me surgen las siguientes preguntas:
Título: Re: Uso de referencias con memoria dinámica [C++] Publicado por: CalgaryCorpus en 30 Marzo 2019, 15:42 pm Si pasas por valor, no lograras que lo que asignes a ese puntero se modifique, pues vas a estar asignandole a una copia.
No hay diferencia de otra manera. Título: Re: Uso de referencias con memoria dinámica [C++] Publicado por: K-YreX en 30 Marzo 2019, 18:44 pm Después de darle unas cuántas vueltas creo que he llegado a una explicación. Si alguien ve algo raro o incorrecto que me lo comente para corregirlo ya que creo que puede servir para gente que tenga dudas con esto :-X
Voy a usar un ejemplo muy sencillo para explicar esto: Código
En la línea 6, declaramos un puntero (almacena una dirección de memoria) <p> y hacemos que apunte a <NULL>. Vamos a suponer que se guarda en la posición de memoria 0x1 (voy a usar posiciones de memoria consecutivas para simplificar el ejemplo). Entonces quedaría así: Código: 0x1(p) = NULL En la línea 7, reservamos memoria para guardar dos enteros. Suponemos que sus posiciones son 0x2 y 0x3 respectivamente y en las líneas 8 y 9 asignamos valores a esas posiciones. Entonces tenemos: Código: 0x1(p) = 0x2 En la línea 10, llamamos a la función <anular()>, la cual recibe el puntero que almacena la dirección de memoria del primer elemento del array. Al ser pasado por valor, se copia el contenido de <p> en <v> (suponemos <v> en 0x4) y el 1 se copia en <pos> (suponemos 0x5). Entonces tenemos antes de ejecutar la función: Código: 0x1(p) = 0x2 Al ejecutar la línea 2, el contenido se modifica en el "array original" (que es siempre el mismo porque sólo tenemos uno). Esto es porque <v> almacena la misma posición de memoria que <p> (OJO: <v> no almacena la posición de memoria dónde se guarda <p>, sino la dirección de memoria que se guarda EN <p>). Por eso para hacer cambios o acciones sobre el array en sí, no es necesario pasarlo por referencia, porque ambos punteros apuntan al mismo sitio. Sin embargo, si tenemos esta alternativa: Código Y queremos reservar memoria, esto es una operación que se debe aplicar, siguiendo con el mismo ejemplo, sobre 0x1 (dirección en la que hemos guardado <p>), no sobre 0x4 (dirección en la que hemos guardado <v>). Al pasar por referencia la tabla de direcciones de memoria anterior quedaría de la siguiente manera: Código: 0x1(p) = 0x2 Entonces mi conclusión es que el paso por referencia es para operar sobre la dirección de memoria DÓNDE está el puntero, no para operar sobre la dirección de memoria que está EN el puntero. Por lo que supongo que a efectos de "eficiencia", es lo mismo hacer un paso por referencia que por valor (en ambos casos pasamos únicamente una dirección de memoria, en un caso la dirección dónde está el puntero y en el otro, la dirección que guarda el puntero) Espero que le sirva a alguien. :-X Título: Re: Uso de referencias con memoria dinámica [C++] Publicado por: Loretz en 31 Marzo 2019, 01:20 am Creo que no está del todo bien.
Pongo acá tu ejemplo añadiendo algunos textos que pueden ayudar: Código
Yo lo diría así: Un puntero es una variable como cualquier otra, en este caso, p es de tipo int*. Como toda variable está en algún lado, se puede tomar su dirección; además se le puede asignar un valor, otra dirección de memoria, aunque esa dirección de memoria que se asigna al puntero puede estar en el free store (memoria libre) o en la pila (stack), a p le da igual. Por ejemplo: Código: int i=5; p = &i; // stack En tu línea 6 tienes declarado el puntero p, pero sin inicializar, no apunta a NULL; probablemente apunte a algo pero no podemos saberlo, intentar acceder a qué apunta un puntero sin inicializar es un error que no debería siquiera compilar. Lo que sí puedes es leer su propia dirección, en dónde está. Entonces, en un puntero tenemos su propia dirección de memoria y la dirección de memoria a la que apunta. Cuando pasas a p como parámetro de anular(), puedes ver que la dirección de v es diferente a la dirección de p, naturalmente, v está en el el stack frame de anular(), pero apunta a la misma dirección que apunta p. Puedes verlo ejecutando mi ejemplo. Si observas los valores reales de las direcciones de memoria a donde apuntan p[0] y p[1] podrás ver que 1) p == &p[0]; 2) &p[1] == &p[0] + sizeof(int*); p y &p[0] podrían llegar a ser de tipos distintos, pero los dos guardan la misma dirección de memoria. Como &p[0] y &p[1] son las direcciones consecutivas en memoria capaces de guardar sendos int(s), deben diferir en sizof(int*), ni más ni menos. Título: Re: Uso de referencias con memoria dinámica [C++] Publicado por: NextByte en 31 Marzo 2019, 05:01 am Creo que no está del todo bien. Pongo acá tu ejemplo añadiendo algunos textos que pueden ayudar: Código
Yo lo diría así: Un puntero es una variable como cualquier otra, en este caso, p es de tipo int*. Como toda variable está en algún lado, se puede tomar su dirección; además se le puede asignar un valor, otra dirección de memoria, aunque esa dirección de memoria que se asigna al puntero puede estar en el free store (memoria libre) o en la pila (stack), a p le da igual. Por ejemplo: Código: int i=5; p = &i; // stack En tu línea 6 tienes declarado el puntero p, pero sin inicializar, no apunta a NULL; probablemente apunte a algo pero no podemos saberlo, intentar acceder a qué apunta un puntero sin inicializar es un error que no debería siquiera compilar. Lo que sí puedes es leer su propia dirección, en dónde está. Entonces, en un puntero tenemos su propia dirección de memoria y la dirección de memoria a la que apunta. Cuando pasas a p como parámetro de anular(), puedes ver que la dirección de v es diferente a la dirección de p, naturalmente, v está en el el stack frame de anular(), pero apunta a la misma dirección que apunta p. Puedes verlo ejecutando mi ejemplo. Si observas los valores reales de las direcciones de memoria a donde apuntan p[0] y p[1] podrás ver que 1) p == &p[0]; 2) &p[1] == &p[0] + sizeof(int*); p y &p[0] podrían llegar a ser de tipos distintos, pero los dos guardan la misma dirección de memoria. Como &p[0] y &p[1] son las direcciones consecutivas en memoria capaces de guardar sendos int(s), deben diferir en sizof(int*), ni más ni menos. ¿ Por qué se dice que la macro NULL no es recomendada en C++ ?, he visto varias fuentes que afirman eso pero no logro entender el por que. Sé que la macro 'NULL' viene desde C y que representa el numero entero 0 y que 'nullptr' fue agregado en C++11 pero ¿ qué problemas puede conllevar el usar la macro 'NULL'. ? Título: Re: Uso de referencias con memoria dinámica [C++] Publicado por: K-YreX en 31 Marzo 2019, 13:47 pm En tu línea 6 tienes declarado el puntero p, pero sin inicializar, no apunta a NULL Tienes razón en esto. Fue fallo mío que pensé en asignarle NULL pero lo olvidé al estar pensando en el resto de la explicación :xDAdemás no conocía la diferencia entre <NULL> y <nullptr> así que gracias también por ello. ¿ Por qué se dice que la macro NULL no es recomendada en C++ ?, he visto varias fuentes que afirman eso pero no logro entender el por que. Sé que la macro 'NULL' viene desde C y que representa el numero entero 0 y que 'nullptr' fue agregado en C++11 pero ¿ qué problemas puede conllevar el usar la macro 'NULL'. ? Por lo que he leído yo es porque <NULL> equivale a un 0 de tipo <int>; mientras que <nullptr> equivale a 0 también (si muestras el valor puedes verlo) siempre sigue siendo de tipo puntero, como dice @Loretz es de tipo <nullptr_t>. Entonces se evita el uso de <NULL> porque puede dar errores de ambigüedad al cambiar el tipo de dato.Como &p[0] y &p[1] son las direcciones consecutivas en memoria capaces de guardar sendos int(s), deben diferir en sizof(int*), ni más ni menos. Es cierto que sus posiciones de memoria deben diferir en el tamaño del tipo de dato que puede almacenar. Pero como comenté, uso posiciones de memoria consecutivas y simples ya que lo que quería que se entendiese era ver de qué posiciones de memoria estamos hablando en cada momento.Gracias por la respuesta ya que me diste la idea de probar el mismo programa para ver las posiciones de memoria que se utilizan. He añadido otra función para que se vea mejor el paso de un puntero por valor y por referencia. Código
Al ejecutarlo obtenemos la siguiente salida (las posiciones de memoria depende de cada ejecución) donde podemos observar que coinciden los valores que comenté en mi anteior explicación: Código: p esta en 0x7fff4ce5ed50 y su contenido es 0 Título: Re: Uso de referencias con memoria dinámica [C++] Publicado por: Loretz en 1 Abril 2019, 02:40 am Citar ¿ Por qué se dice que la macro NULL no es recomendada en C++ ? Acá va un ejemplo donde se invocan distintas funciones sobrecargadas: Código: #include <iostream> Además la constante nullptr (de tipo nullptr_t): - Puede convertirse a cualquier tipo de puntero o puntero a miembro y a bool, pero a nada más. - No puede ser usada en expresiones aritméticas. - Puede comparase con el int 0 [[ como en if(p == 0) ]] - Puede usarse en expresiones relacionales (expresiones que se evalúan a true o false) para compararse con punteros (u otro dato de tipo nullptr_t). De todos modos, por una cuestión de compatibilidad, aún en C++17 es aceptable asignar 0 (o NULL) a un puntero, como en Código: char* pch = 0; |