oop - Fortran 构造函数返回指向已分配对象的指针
问题描述
在这个问题中:Fortran Functions with a pointer result in a normal assignment,指出不推荐使用返回指针的函数。
我的问题涉及用户定义类型的构造函数。考虑下面的代码:
program PointTest
use PointMod, only: PointType
implicit none
class(PointType), allocatable :: TypeObject
TypeObject = PointType(10)
end program PointTest
module PointMod
implicit none
type PointType
real(8), dimension(:), allocatable :: array
contains
final :: Finalizer
end type PointType
interface PointType
procedure NewPointType
end interface PointType
contains
function NewPointType(n) result(TypePointer)
implicit none
integer, intent(in) :: n
type(PointType), pointer :: TypePointer
allocate(TypePointer)
allocate(TypePointer%array(n))
end function NewPointType
subroutine Finalizer(this)
implicit none
type(PointType) :: this
print *, 'Finalizer called'
end subroutine Finalizer
end module PointMod
在代码中,我定义了一个带有构造函数的类型,该构造函数分配对象,然后在对象中分配一个数组。然后它返回一个指向该对象的指针。
如果构造函数只返回对象,则对象和数组将被复制然后释放(至少使用标准兼容编译器)。这可能会导致开销并扰乱我们的内存跟踪。
使用 ifort 编译上面的代码不会使用 -warn all 发出警告(终结器中未使用的变量除外),并且代码的行为方式符合我的预期。它也适用于 gfortran,除了我在使用 -Wall 时收到警告
TypeObject = PointType(10)
1
Warning: POINTER-valued function appears on right-hand side of assignment at (1) [-Wsurprising]
使用这样的构造函数有什么风险?据我所知,不会有悬空指针,我们将对何时分配对象有更多控制权。可以达到相同结果的一种解决方法是显式分配对象并将构造函数转换为设置变量并分配数组的子例程,但它看起来不那么优雅。还有其他解决方案吗?我们的代码采用 Fortran 2008 标准。
解决方案
不要使用指针值函数。作为一项规则,我从不创建返回函数的函数。它们很糟糕而且令人困惑。它们会导致令人讨厌的错误,尤其是当混淆=>
和=
.
该函数所做的是分配一个新对象并创建一个分配该对象的指针。
什么
TypeObject = PointType(10)
所做的是它复制存储在指针中的对象的值。然后指针被遗忘,指针指向的内存被泄露并永远丢失。
你写“据我所知,不会有悬空指针,我们将对何时分配对象有更多的控制权。” 但是,我没有看到避免在函数内部分配悬空指针的方法。甚至终结器也无济于事。我也看不出你有更多的控制权。您明确分配的内存刚刚丢失。您有不同的内存TypeObject
(可能在主程序的堆栈上),并且类型内部的数组将在内部赋值的复制过程中再次被分配TypeObject = PointType(10)
。
终结器可以处理数组组件,因此函数内部分配的数组不必丢失。但是,指针TypePointer
指向的类型本身,以及它的不可分配的非指针组件和描述符等,不能从终结器中释放,并且将保持悬空状态并且内存将被泄漏。
不要害怕将对象作为值返回的函数。那不是问题。编译器很聪明,能够优化不必要的副本。编译器可能很容易发现您只是在分配函数结果,因此它可以将分配目标的内存位置用于函数结果变量(如果它不必是可分配的)。
存在许多其他优化。
function NewPointType(n) result(TypePointer)
integer, intent(in) :: n
type(PointType) :: TypePointer
allocate(TypePointer%array(n))
end function NewPointType
更简单,应该可以正常工作。通过优化,它甚至可以更快。如果无法使用非指针不可分配的结果,请使用可分配的。不要将指针用于函数结果。
推荐阅读
- php - 显示假结果,而查询返回真
- r - 有一条线穿过它们的子图
- bluetooth-lowenergy - BLE 读取不正确?
- swift - CoreML 模型预测不同于训练
- java - JDK8 -> JDK10:PKIX 路径构建失败:SunCertPathBuilderException:无法找到请求目标的有效认证路径
- laravel - Vuetify - 在点击事件上添加加载层叠加
- apache - 无法访问抛出此站点的 Apache2 虚拟主机
- c# - 在存储过程中添加一对多记录
- ssh - 如何使用 scp 通过 ssh 转发的堡垒从服务器获取文件?
- swift - 导航到另一个屏幕时,导航栏颜色显示一段时间为白色,原始颜色为红色