简体   繁体   English

Fortran 构造函数返回指向已分配对象的指针

[英]Fortran constructor returning pointer to allocated object

In this question: Fortran Functions with a pointer result in a normal assignment , it is stated that functions returning pointers are not recommended.在这个问题中: Fortran Functions with a pointer result in a normal assignment ,声明不推荐函数返回指针。

My question concerns constructors of user defined types.我的问题涉及用户定义类型的构造函数。 Consider the code below:考虑下面的代码:

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

In the code, I have defined a type with a constructor that allocates the object and then allocates an array in the object.在代码中,我定义了一个带有构造函数的类型,该构造函数分配对象,然后在对象中分配一个数组。 It then returns a pointer to the object.然后它返回一个指向该对象的指针。

If the constructor just returned the object, the object and the array would be copied and then deallocated (at least with standard compliant compilers).如果构造函数刚刚返回对象,则对象和数组将被复制然后释放(至少使用符合标准的编译器)。 This could cause overhead and mess with our memory tracking.这可能会导致开销和内存跟踪混乱。

Compiling the above code with ifort gives no warnings with -warn all (except unused variable in the finalizer) and the code behaves the way I expect.使用 ifort 编译上面的代码不会给出 -warn all 的警告(终结器中未使用的变量除外),并且代码的行为符合我的预期。 It also works fine with gfortran, except I get a warning when using -Wall它也适用于 gfortran,除非我在使用 -Wall 时收到警告

    TypeObject = PointType(10)
                1
Warning: POINTER-valued function appears on right-hand side of assignment at (1) [-Wsurprising]

What are the risks of using constructors like these?使用这样的构造函数有什么风险? As far as I can tell, there will be no dangling pointers and we will have more control on when objects are allocated.据我所知,不会有悬空指针,我们将在分配对象时有更多的控制权。 One workaround that would achieve the same result is to explicitly allocate the object and turn the constructor into a subroutine that sets variables and does the allocation of array, but it looks a lot less elegant.实现相同结果的一种解决方法是显式分配对象并将构造函数转换为设置变量和分配数组的子例程,但它看起来不太优雅。 Are there other solutions?还有其他解决方案吗? Our code is in the Fortran 2008 standard.我们的代码符合 Fortran 2008 标准。

Do not use pointer valued functions.不要使用指针值函数。 As a rule I never make functions that return functions.通常,我从不创建返回函数的函数。 They are bad and confusing.他们是坏的和混乱的。 They lead to nasty bugs, especially when one confuses => and = .它们会导致令人讨厌的错误,尤其是当人们混淆=>=

What the function does is that it allocates a new object and creates a pointer that allocates the object.该函数所做的是分配一个新对象并创建一个分配该对象的指针。

What什么

TypeObject = PointType(10)

does is that it copies the value of the object stored in the pointer.它的作用是复制存储在指针中的对象的值 Then the pointer is forgotten and the memory where the pointer had pointed is leaked and lost forever.然后指针被遗忘,指针指向的内存被泄漏并永远丢失。


You write "As far as I can tell, there will be no dangling pointers and we will have more control on when objects are allocated."你写道: “据我所知,不会有悬空指针,我们将在分配对象时有更多的控制权。” However, I do not see a way to avoid the dangling pointer allocated inside the function.但是,我没有看到避免在函数内部分配悬空指针的方法。 Not even a finalizer can help here.在这里,即使是终结器也无济于事。 I also do not see how you have more control.我也看不出你有更多的控制权。 The memory you explicitly allocated is just lost.您明确分配的内存只是失去了。 You have a different memory for TypeObject (likely on the main program's stack) and the array inside the type will get allocated again during the copy at the intrinsic assignment TypeObject = PointType(10) .您有一个不同的TypeObject内存(可能在主程序的堆栈上),并且类型内部的数组将在内部赋值TypeObject = PointType(10)的复制期间再次分配。

The finalizer could take care of the array component so the array allocated inside the function does not have to be lost.终结器可以处理数组组件,因此函数内部分配的数组不必丢失。 However, the type itself, to which the pointer TypePointer points, with its non-allocatable non-pointer components and descriptors and so on, cannot be deallocated from the finalizer and will remain dangling and the memory will be leaked.但是,指针TypePointer指向的类型本身及其不可分配的非指针组件和描述符等无法从终结器中释放,并且将保持悬空状态并且内存将泄漏。


Do not be afraid of functions that return objects as values.不要害怕将对象作为值返回的函数。 That is not a problem.那不是问题。 Compilers are smart and are able to optimize an unnecessary copy.编译器很聪明,能够优化不必要的副本。 Compiler might be easily able to find out that you are just assigning the function result so it can use the memory location of the assignment target for the function result variable (if it does not have to be allocatable).编译器可能很容易发现您只是在分配函数结果,因此它可以将分配目标的内存位置用于函数结果变量(如果它不必是可分配的)。

Many other optimizations exist.存在许多其他优化。

   function NewPointType(n) result(TypePointer)   
      integer, intent(in) :: n

      type(PointType) :: TypePointer

      allocate(TypePointer%array(n))    
   end function NewPointType

is simpler and should work just fine.更简单,应该可以正常工作。 With optimizations it could even be faster.通过优化,它甚至可以更快。 If using a non-pointer non-allocatable result is not possible, use allocatable.如果无法使用非指针不可分配的结果,请使用可分配的。 Do not use pointers for function results.不要对函数结果使用指针。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM