fortran - que - ¿La regla de variable inicializada localmente también se aplica a los punteros?
punteros y vectores en c (2)
La sección (5.2.3) del estándar F2008 referente al atributo SAVE
implícito no distingue entre los casos de POINTER
o not- POINTER
.
Como un lado, mientras que un puntero adquirirá el atributo, para punteros, SAVE
significa algo ligeramente diferente:
[...] a menos que sea un puntero y su objetivo se vuelva indefinido
Ver la respuesta de @VladimirF (que me impulsó a aclarar aquí) para obtener más información. Sin embargo, tenga en cuenta que pensar erróneamente que un puntero nulo-inicializado es anulado en cada entrada de un alcance es quizás peor que pensar que una variable tiene asignado cero cada vez: simplemente probar ASSOCIATED(ke)
no es estándar si ke
tiene un estado de asociación de puntero indefinido .
Yendo a sus ejemplos, tiene la "MANERA INCORRECTA" y la "MANERA CORRECTA" al revés: la "MANERA INCORRECTA" es la forma correcta de inicializarse, y la "MANERA CORRECTA" es la forma incorrecta de inicializarse. Es decir, solo en el primer caso ocurre cualquier inicialización.
Editar, siguiendo la actualización de la pregunta:
Las variables con el atributo del pointer
no son diferentes de las variables sin cuando se trata de la inicialización: si una variable tiene una inicialización explícita, adquiere el atributo save
. Si desea que una variable no tenga este atributo, no se puede inicializar explícitamente. [Esta es una respuesta más explícita a la pregunta original de lo que pude haber hecho antes].
Hay consejos por ahí acerca de siempre "inicializar" punteros. En palabras de MR & C que generalmente tienen buenos consejos:
Nuestra recomendación es que todos los punteros estén tan inicializados para reducir el riesgo de efectos extraños por el uso accidental de punteros indefinidos. También es una ayuda para escribir código que evita fugas de memoria.
El "inicializado" aquí, sin embargo, incluye "anulado al principio de la subrutina", así como la inicialización explícita.
Sin embargo, no es un requisito. Si un puntero debe asociarse con otra cosa, no tiene que ser (pero podría ser) anulado primero. E incluso un buen consejo no es una excusa para evitar ser cuidadoso.
Pero aún se cumple, que si save
no es bueno, entonces la inicialización explícita no es buena.
Además, es posible que hayas visto que es bueno que los componentes de puntero de un tipo derivado tengan una inicialización predeterminada. Este es un consejo sensato.
Sé que uno debe tener cuidado al inicializar una variable declarada localmente ( referencia ).
! ESTA ES LA FORMA INCORRECTA (Una variable local que se inicializa cuando se declara tiene un atributo de guardado implícito).
real function kinetic_energy(v)
real, dimension(:), intent(in) :: v
real :: ke = 0.0
end function kinetic_energy
! ESTA ES LA MANERA CORRECTA
real function kinetic_energy(v)
real, dimension(:), intent(in) :: v
real :: ke
ke = 0.
end function kinetic_energy
Me pregunto si también tenemos algo así como punteros o no.
real function kinetic_energy(v)
real, dimension(:), intent(in) :: v
real, pointer :: ke => null()
end function kinetic_energy
o
real function kinetic_energy(v)
real, dimension(:), intent(in) :: v
real, pointer :: ke
nullify(ke)
end function kinetic_energy
Una variable de puntero que se anula cuando se declara se consideraría como un atributo de guardado.
Gracias por la información útil. He leído que siempre inicializar punteros a NULL, basado en lo que dijiste, esta podría ser una afirmación totalmente incorrecta. Por ejemplo, ¡no debería inicializar mis variables de puntero locales dentro de mis subrutinas! (si se asignan al nuevo tamaño en cada entrada a la subrutina) ¡Tengo razón!
real function kinetic_energy(v)
real, dimension(:), intent(in) :: v
!local variables
real, dimension(:), pointer :: ke => null()
integer :: n
!
n=size(v,1)
allocate(ke(n))
!make a copy
ke=v
!do some computation ...
end function kinetic_energy
La situación para el puntero y los no identificadores es realmente casi la misma. @francescalus tiene razón en que la regla 5.3.16.1
habla de la posibilidad de que el puntero se vuelva indefinido, pero no es importante aquí. Por supuesto, si el puntero guardado apunta a algo de corta vida, no será válido después de que el objetivo dejó de existir, pero eso es bastante obvio.
Pero la semántica de la inicialización explícita es la misma para los punteros y los no punteros. Implica el atributo save
. Eso significa que el valor o la asociación del puntero se conserva entre invocaciones de procedimiento y, por lo tanto, que la inicialización se realiza solo una vez (sus versiones 1 y 3). Si desea asignar el valor deseado en cada invocación de procedimiento, debe usar la asignación ejecutable normal, no la expresión de inicialización explícita u otras instrucciones ejecutables (sus versiones 2 y 4).
Editar:
En cuanto a su nuevo (último) ejemplo, este parece un lugar para usar allocatable
lugar de pointer
para mí. Nunca están indefinidos, pero comienzan como not allocated
.
Si necesita que sea un puntero, no tiene que ser anulado antes de la asignación necesariamente si no prueba su estado de asociación. Siempre puede usar nullify()
al comienzo del código ejecutable.