指向包含可分配数组的派生类型的指针

Posted

技术标签:

【中文标题】指向包含可分配数组的派生类型的指针【英文标题】:Pointer to derived type that contains allocatable array 【发布时间】:2016-12-17 16:11:21 【问题描述】:

一般来说,我想重命名通过子例程参数传递的派生类型中的可分配变量。用 'derived%type_xx' 写所有东西并不是那么令人愉快。此外,我不想花费额外的内存将派生类型的值复制到一个新变量,这会花费新分配的内存。此外,由于许多原因,我知道可分配数组比指针更受欢迎。我尝试定义指向可分配变量的指针,但失败了。我尝试这样做是因为我想简化我的代码,既要可读又不要太长。我想知道是否有实现目标的方法?谢谢。

下面是演示代码:

Module module_type
IMPLICIT NONE
    TYPE type_1
        REAL,ALLOCATABLE                  ::      longname_1(:), longname_2(:)
    END TYPE
END MODULE

!------------------------------------------------------------------------------------------
SUBROUTINE TEST(input)
    USE MODULE module_type
IMPLICIT NONE
    TYPE(type_1)                          ::      input
    input%longname_1 = input%longname_1 + input%longname_2   ! Use one line to show what I mean
END SUBROUTINE

这就是失败的原因:

Module module_type
IMPLICIT NONE
    TYPE type_1
        REAL,ALLOCATABLE                  ::      longname_1(:), longname_2(:)
    END TYPE
END MODULE

!------------------------------------------------------------------------------------------
SUBROUTINE TEST(input)
    USE MODULE module_type
IMPLICIT NONE
    TYPE(type_1),TARGET                    ::      input

    REAL,POINTER                           ::      a => input%longname_1 &
                                                 & b => input%longname_2

    a = a + b   ! much better for reading
END SUBROUTINE

这似乎是一个小问题,但我想在将来阅读我的代码时不会感到太痛苦。那么最好的选择是什么?非常感谢。

【问题讨论】:

【参考方案1】:

您可以使用 ASSOCIATE 构造将简单名称与更复杂的指示符或表达式相关联。

您还可以将派生类型的子对象用作执行操作的过程的实际参数。

你的指针方法失败了,因为你有一个等级不匹配 - 你试图将标量指针与数组目标相关联。如果您的过程的显式接口在调用范围内不可用,您也可能遇到问题。带有 TARGET 属性的虚拟参数的过程需要显式接口。

对这种简单的名称别名使用指针可能会降低编译器优化代码的能力。应该首选 ASSOCIATE 之类的东西。

【讨论】:

非常感谢!【参考方案2】:

更新:@IanH 发表评论后,我回去检查:我完全错误地解释了您的代码失败的原因。正如他在回答中指出的那样,主要问题是指针和目标必须具有相同的等级,因此您必须将 ab 声明为:

real, pointer :: a(:), b(:)

其次,在将这些指针实际指向目标之前,必须先分配目标。这是一个有效的示例:

program allocatable_target

    implicit none
    type :: my_type
        integer, allocatable :: my_array(:)
    end type my_type
    type(my_type), target :: dummy
    integer, pointer :: a(:)

    allocate(dummy%my_array(10))
    a => dummy%my_array
    a = 10
    print *, dummy%my_array

end program allocatable_target

如果您有与 Fortran 2003 兼容的编译器,则可以使用 associate -- 专门针对此类问题。这是一个例子:

program associate_example

    implicit none
    type :: my_type
        integer, allocatable :: long_name_1(:), long_name_2(:)
    end type my_type

    type(my_type) :: input

    integer :: i
    allocate(input%long_name_1(100), input%long_name_2(100))

    associate (a=>input%long_name_1, b=>input%long_name_2)
        a = (/ (i, i = 1, 100, 1) /)
        b = (/ (2*i+4, i = 1, 100, 1) /)
        a = a + b
    end associate

    print *, input%long_name_1

end program associate_example

associate 块内,您可以使用ab 作为声明的更长命名变量的简写形式。

但除此之外,我建议您使用具有正确代码完成功能的编辑器,这样长变量名就不再是什么大问题了。目前我正在尝试Atom,对此我很满意。但我已经使用 vim 和适当的扩展很长时间了。

【讨论】:

感谢您展示相关构造的详细使用! 警告:如果选择器具有allocatablepointer 属性,则 associate_name 不会继承该属性。但是,如果选择器是一个数组,则 associate_name 将假定每个维度的等级和上下限相同,如果选择器是虚拟变量并具有 intenttargetvolatile 属性,则 associate_name 假定相同的属性。

以上是关于指向包含可分配数组的派生类型的指针的主要内容,如果未能解决你的问题,请参考以下文章

在 C++ 中将派生类对象分配和访问到基类“指向指针”对象

关于C++基类、派生类的引用和指针

Fortran - 可分配派生类型的可分配数组

通过指向派生类的指针访问派生成员变量

声明指向基类和派生类的指针

有没有办法在不知道派生类型的情况下将包含派生指针的 std::any 转换为基指针?