Используется ли правило инициализации с локальным инициализацией для указателей?

Я знаю, что при инициализации локально объявленной переменной нужно быть осторожным (ссылка).

! ЭТО НЕПРАВИЛЬНЫЙ ПУТЬ (Локальная переменная, которая инициализируется при объявлении, имеет неявный атрибут сохранения.)

real function kinetic_energy(v)
 real, dimension(:), intent(in) :: v
 real :: ke = 0.0
 end function kinetic_energy

! ЭТО ПРАВИЛЬНЫЙ ПУТЬ

real function kinetic_energy(v)
 real, dimension(:), intent(in) :: v
 real :: ke
 ke = 0.
 end function kinetic_energy

Мне интересно, есть ли у нас что-то подобное для указателей или нет.

real function kinetic_energy(v)
 real, dimension(:), intent(in) :: v
 real, pointer :: ke => null()
 end function kinetic_energy

или

real function kinetic_energy(v)
 real, dimension(:), intent(in) :: v
 real, pointer :: ke
 nullify(ke)
 end function kinetic_energy

Переменная указателя, которая объявляется с нулевым значением, считается атрибутом сохранения!

Спасибо за полезную информацию. Я прочитал, что всегда инициализирую указатели на NULL, основываясь на том, что вы сказали, что это может быть абсолютно неправильный оператор. Например, я не должен инициализировать мои локальные переменные-указатели внутри моих подпрограмм! (если они назначаются на новый размер при каждой записи в подпрограмму) Я прав!

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
2 ответа

Ситуация для указателей и неточечных сигналов практически одинакова. @francescalus прав, что правило 5.3.16.1 действительно говорит о возможности того, что цель указателя станет undefined, но здесь это не важно. Конечно, если сохраненный указатель указал на что-то недолговечное, это не будет действовать после того, как цель перестанет существовать, но это совершенно очевидно.

Но семантика явной инициализации одинакова для указателей и не указателей. Он подразумевает атрибут save. Это означает, что ассоциация значений или указателей сохраняется между вызовами процедур и поэтому инициализация выполняется только один раз (ваши версии 1 и 3). Если вы хотите назначить требуемое значение при каждом вызове процедуры, вы должны использовать стандартное исполняемое присваивание, а не явное выражение инициализации или другие исполняемые операторы (ваши версии 2 и 4).

Edit:

Что касается вашего нового (последнего) примера, это выглядит как место для использования allocatable вместо pointer для меня. Они никогда не undefined, а начинаются как not allocated.

Если вам нужно, чтобы он был указателем, он все равно не должен быть аннулирован до выделения обязательно, если вы не проверяете его статус ассоциации. Вы всегда можете использовать nullify() в начале исполняемого кода.


В разделе (5.2.3) стандарта F2008, относящемся к неявному атрибуту SAVE, не проводится различие между случаями POINTER или not- POINTER.

В стороне, в то время как указатель получит атрибут, для указателей SAVE означает что-то немного другое:

[...], если это не указатель, и его цель становится undefined

См. ответ @VladimirF (который побудил меня разъяснить здесь) для большего. Заметьте, однако, что ошибочное мышление нулевой инициализации указателя с нулевым значением для каждой записи в область видимости, возможно, хуже, чем думать, что переменная присваивается нулю каждый раз: простое тестирование ASSOCIATED(ke) является нестандартным, если ke имеет undefined статус ассоциации указателя.

Переходя к вашим примерам, у вас есть неправильный путь "НЕПРАВИЛЬНЫЙ ПУТЬ" и "ПРАВИЛЬНЫЙ ПУТЬ": "НЕПРАВИЛЬНЫЙ ПУТЬ" - это правильный способ инициализации, а "ПРАВОЙ ПУТЬ" - неправильный способ инициализации. То есть, только в первом случае происходит любая инициализация.

Изменить, после обновления вопроса:

Переменные с атрибутом POINTER не отличаются от переменных без необходимости инициализации: если переменная имеет явную инициализацию, она получает атрибут SAVE. Если вы хотите, чтобы переменная не имела этого атрибута, то она не может быть явно инициализирована. [Это более явный ответ на исходный вопрос, чем я мог раньше.]

Существует совет о всегда "инициализации" указателей. По словам MR & C, которые обычно имеют хороший совет:

Наша рекомендация состоит в том, чтобы все указатели были инициализированы таким образом, чтобы уменьшить риск причудливых эффектов от случайного использования указателей undefined. Это тоже помогает при написании кода, который позволяет избежать утечек памяти.

"Инициализированный" здесь, тем не менее, включает в себя "аннулирование в начале подпрограммы", а также явную инициализацию.

Однако это не является обязательным требованием. Если указатель должен быть связан с чем-то другим, он не обязательно должен быть (но может быть) аннулирован первым. И даже хороший совет не является оправданием, чтобы не быть осторожным.

Но он по-прежнему сохраняет, что если SAVE не является хорошим, то явная инициализация не является хорошей.

Кроме того, возможно, что вы видели, как он хорошо разбирается в компонентах-указателях производного типа, имеющих инициализацию по умолчанию. Это разумный совет.

licensed under cc by-sa 3.0 with attribution.