#fortran #intel-fortran
#fortran #intel-fortran
Вопрос:
У меня есть следующий код, который вызывает ошибку сегментации. Он жалуется, что
forrtl: серьезный (408): fort: (7): Попытка использовать указатель TT, когда он не связан с целью
Теперь я почти уверен, в чем причина, а именно, он пытается получить доступ к моей copy
процедуре назначения, в то время как я просто пытаюсь инициализировать объект.
Путем закомментирования generic :: assignment(=) => copy
это работает отлично!
Я компилирую код следующим образом: (IFORT версии 19.0.3) ifort -O0 -debug full -check all -traceback -g -C -CB -CU -CA -fpp filaname.f90
и запускаю с помощью ./a.out
module md
implicit none
type T_TEST
integer :: ii
contains
procedure, pass(this) :: COPY
generic :: assignment(=) => copy
end type
interface t_test
module procedure init
end interface t_test
type(t_test) , allocatable :: tt
contains
function init( size )
integer, intent(in) :: size
type(t_test) , allocatable :: init
allocate( init )
init% ii = size
end function
subroutine copy(this, old )
class(t_test), intent(out) ::this
type(t_test), intent(in) :: old
this% ii = old% ii
end subroutine
end module md
program t_Testprogram
use md
implicit none
tt = t_test( 100 )
end program t_Testprogram
Комментарии:
1. В вашем коде нет указателя, просто выделяемый. Вы на 100% уверены, что показываете точный код, который выдает ошибку?
2. Да, безусловно. Я только что проверил еще раз. Если вы компилируете с показанными флагами, я бы хотел, чтобы вы получили то же сообщение об ошибке, что и при использовании ifort
3. Я только что попробовал gfortran, и он просто выдает
segmentation fault - invalid memory reference
. Опять же, это говорит о том, что вызовtt = t_test( 100 )
каким-то образом заканчивается в процедуре назначения копирования. Потому что, когда я комментирую общее назначение, оно работает отлично.#4. Ну, конечно, это относится к
copy
общему назначению. Вот почему у вас это есть, чтобы вызываться, когда=
есть в коде, не так ли?
Ответ №1:
Причина в том, что перегруженное назначение copy
не поддерживает выделяемые левые части. Таким образом, когда значение this
используется в this% ii = old% ii
, оно фактически не существует и используется нулевой указатель. Но я согласен, что сообщение об ошибке Intel сбивает с толку или даже неверно.
Автоматическое выделение левой части (повторное) применяется только к интризичным назначениям, а не к определяемым пользователем. В пользовательских вы должны сами запрограммировать точное поведение. И вы ничего не указали для не выделенных левых сторон.
Это работает для меня:
type T_TEST
integer :: ii
end type
interface assignment(=)
procedure copy
end interface
subroutine copy(this, old )
class(t_test), allocatable, intent(out) ::this
type(t_test), intent(in) :: old
if (.not.allocated(this)) allocate(this)
this% ii = old% ii
end subroutine
Или вы можете просто сначала выделить объект (это то, что я бы сделал здесь, потому что gfortran, похоже, не нравится общее разрешение на основе атрибута allocatable — функции F08).
allocate(tt)
tt = t_test( 100 )
Похоже, вы думаете, что только потому, что у конструктора есть переменная результата «marked» allocatable
, он выделит левую часть назначения для вас. Это не так. Единственное, что он делает, это то, что он выделяет свой собственный результат в качестве временной переменной. Затем этот результат присваивается в tt = t_test()
, а затем автоматически освобождается.
Помните, что результирующая переменная не совпадает с левой частью назначения. Результат может быть использован в выражении многих различных типов, а не только в присваивании. Это может быть передано подпрограмме, это может быть использовано в арифметическом выражении, это может быть напечатано…
Ваш конструктор может быть просто
function init( size )
integer, intent(in) :: size
type(t_test) :: init
init% ii = size
end function
и результат будет точно таким же. Нет причин делать его распределяемым, это просто усложняет его, но ни в малейшей степени не меняет результат.
Возможно, вы пытаетесь следовать некоторым принципам C RAII, но помните, что C — это просто не Fortran.
Комментарии:
1. Чего я хотел, так это: если я скажу tt = t_test (100), он должен действовать как конструктор. Таким образом, у меня есть интерфейс процедуры модуля для инициализации. Хотя позже, если я сделаю tt1 = tt2 , это должна быть процедура назначения копии. Да, идея заключается в том, что когда LHS является распределяемым, он должен быть конструктором, а не в том случае, когда он выделяется. Можете ли вы объяснить, почему компилятор решает обратиться к процедуре копирования, когда я выполняю tt = t_test (100). Я уже определил, что
t_test
должно ссылаться наINIT
подпрограмму2. @A2LBK
t_test(100)
действительно создает значение, но затем оно должно быть присвоеноtt
. Вот почему должно быть вызвано пользовательское назначение.3. @A2LBK Вы, кажется, используете терминологию C , это бесполезно, Fortran сильно отличается от C .
4. «идея заключается в том, что, когда LHS является распределяемым, он должен быть конструктором, а не в том случае, когда он выделяется». Стандарт Fortran не поддерживает никаких подобных идей, это просто ваше желание.
5. Ах, теперь я понимаю, почему это попадает в копию. Спасибо! Обычно я использовал конструкторы такого типа, поскольку это было то, что многие советовали при попытке создать конструкторы в Fortran. Но я понимаю, почему это может легко привести к конфликту. Таким образом, в принципе, более или менее невозможно одновременно иметь конструктор и копировать назначение в одном объекте