不复制Fortran派生类型的指针成员

时间:2018-06-12 23:32:54

标签: fortran

当我初始化函数或子例程中的对象并尝试返回它时,在构造函数中设置的指针成员似乎变得未定义(尽管我可能会误解正在发生的事情)。

我想准确理解这里发生了什么,如果可能的话,如何在构造函数中初始化指针,然后在保留指针的同时从函数或子例程返回对象。

MWE:

#include <vector>
#include <iostream>

template<class T>class LinAlg
{
private:
    std::vector<T> mVector;
    int mSize;
public:
    LinAlg(int size);
    T & operator[](int i); 
    T const & operator[] (int i)const;
};

template<class T> LinAlg<T>::LinAlg(int size)
{
    mSize = size;
    std::vector<T> mVector;
    for (int i=0; i<mSize; i++)
    {
        mVector.push_back(0);
    }
}

template<class T> T &  LinAlg<T>::operator[](int i)
{
    return mVector[i];
}

template<class T> T const& LinAlg<T>::operator[](int i)const
{
    return mVector[i];
}

int main()
{
  LinAlg<double> vec(2);
  vec[0] = 1.0; 
  vec[1] = 1.0; 
  for(int i=0; i<2; i++)
  {
      std::cout << vec[i] << '\n'; 
  }
    return 0;
}

使用gfortran 5.4.0,

program mwe
  implicit none

  type a
    integer var
  end type a

  type b
    type(a), pointer :: elt
  end type b

  interface b
    procedure construct_b
  end interface

  type(b) val_func, val_sub

  val_func = get_new_b(52)
  write(*,*) 'using function: ', val_func%elt%var

  call new_b(val_sub, 55)
  write(*,*) 'using subroutine: ', val_sub%elt%var

contains

  function construct_b(elt) result(r)
    class(a), target, intent(in) :: elt
    type(b) r

    r%elt => elt
  end function

  function get_new_b(n) result(r)
    integer, intent(in) :: n
    type(b) r

    type(a) elt

    elt = a(n)
    r = b(elt)
    write(*,*) 'get_new_b:      ', r%elt%var
  end function

  subroutine new_b(r, n)
    type(b), intent(inout) :: r
    integer, intent(in) :: n

    type(a) elt

    elt = a(n)
    r = b(elt)
    write(*,*) 'new_b:            ', r%elt%var
  end subroutine

end program mwe

我期望的输出是:

$ gfortran -o mwe.x mwe.f90
$ ./mwe.x
 get_new_b:                52
 using function:    127919104
 new_b:                      55
 using subroutine:    127919104

1 个答案:

答案 0 :(得分:2)

get_new_b程序中,您正在执行:

type(a) elt    
elt = a(n)
r = b(elt)

这意味着您正在函数内部创建局部变量elt,然后您使用此变量调用constructor_b(通过b接口)。在constructor_b内,会发生什么:

type(b) r
r%elt => elt

即,您创建了一个新的type(b)变量,并在其elt字段与您传入的变量elt之间执行指针关联。

问题是:您作为参数传递的实际参数elt local 到函数get_new_b的范围。当控件返回主程序时,指针的目标(在函数内创建的elt变量)不再存在,指针就会“悬空”。

你永远不应该有一个指向超出范围的变量的指针。

在您提供的代码中,拥有可分配组件更有意义。只有当你想将它指向其他现有变量时才会有一个指针组件(其内存由你的代码的其他部分管理,而不是由类型本身管理)。

但是如果指针是你想要的,那么确保它的目标永远不会在带有指针组件的变量之前被定义。