含指针的Fortran类型实例的正确分配方式
Fortran含指针成员类型的安全初始化方式
示例代码
module lib private type node integer::val type(node),allocatable::next end type type,public::list integer::num=0 ! `first` should be a pointer to avoid making `this` a target in procedures. type(node),pointer::first=>null(),last=>null() contains procedure::add=>list_add final::list_final end type interface list procedure list_new end interface contains function list_new()result(this) type(list)::this print*,'list_new' allocate(this%first) this%last=>this%first end subroutine list_add(this,val) class(list),intent(inout)::this integer,intent(in)::val print*,'list_add' this%num=this%num+1 allocate(this%last%next) this%last=>this%last%next this%last%val=val end subroutine list_final(this) type(list),intent(inout)::this print*,'list_final' ! Checking if `first` is associated is necessary to avoid the error on ! finalization of uninitialized instances. if(associated(this%first))deallocate(this%first) end end program prog use lib type(list)::obj ! type(list),allocatable::obj obj=list() ! allocate(obj,source=list()) call obj%add(42) end
问题现象
这是一段用可分配节点实现链表的Fortran代码,first被设为指针并在构造函数list_new中分配内存,list_final终结过程负责自动释放内存避免泄漏。但使用gfortran-13.1.0加-g选项编译运行时,会在allocate(this%last%next)行触发运行时错误:
Fortran runtime error: Attempting to allocate already allocated variable 'this'
错误发生前的输出为:
list_new list_final list_final list_add
原因分析
list_final被调用了两次:
- 第一次终结声明
type(list)::obj时创建的默认初始化实例; - 第二次终结
obj=list()右侧生成的临时实例——临时实例的内容复制给obj后,其终结过程释放了自身first指向的内存,但obj%first已指向同一块内存,导致obj的指针变为悬空状态,后续调用list_add时触发错误。
解决方案
将type(list)::obj替换为type(list),allocatable::obj,同时把obj=list()替换为allocate(obj,source=list()),即可解决问题,且此时list_final不会被调用。
核心问题解答
带source的allocate并非此类类型实例初始化的唯一正确方式,但确实是无需重新定义赋值操作、无需用显式析构替代final的前提下,最安全简洁的方式之一。其他可行方案包括:
- 自定义赋值运算符:在赋值时实现指针的深拷贝,避免原实例与目标实例共享内存。但这种方式需要编写额外的赋值过程代码,维护成本较高。
- 调整类型成员设计:将
first从指针改为可分配成员,利用Fortran默认赋值的深拷贝特性自动管理内存,无需手动处理指针生命周期。但这需要适配原代码的设计需求。
而obj=list()这种写法的问题根源在于,Fortran默认赋值对指针成员执行浅拷贝——仅复制指针地址而非指向的内存块。当临时实例被终结释放内存后,目标实例的指针就会变为悬空状态,进而触发运行时错误。这种写法虽看似简洁,但对于含指针成员且带有终结过程的类型,存在明确的安全风险。
内容的提问来源于stack exchange,提问作者V T
相关产品推荐
相关产品推荐

