2

I have the following code which is producing a segmentation fault. It does complain that

forrtl: severe (408): fort: (7): Attempt to use pointer TT when it is not associated with a target

Now I am pretty sure what the reason is, namely, it is trying to access my copy assignment routine, while I am just trying to initialise the object.

By commenting out generic :: assignment(=) => copy it works fine!

I am compiling the code as follows : (IFORT version 19.0.3) ifort -O0 -debug full -check all -traceback -g -C -CB -CU -CA -fpp filaname.f90 and running by ./a.out

   module md

   implicit none

   type T_TEST

      integer :: ii

   contains
         procedure, pass(this)               :: COPY
       generic :: assignment(=) => copy

   end type


   interface t_test
      module procedure init
   end interface t_test


   type(t_test) , allocatable :: tt


contains
   function init( size )
      integer, intent(in)                   :: size
      type(t_test) , allocatable           :: init


      allocate( init )
      init% ii = size
   end function

   subroutine copy(this, old )

      class(t_test), intent(out)  ::this
      type(t_test), intent(in) :: old


       this% ii = old% ii

   end subroutine

end module md

program t_Testprogram
use md
implicit none

tt = t_test( 100 )

end program t_Testprogram
ATK
  • 1,296
  • 10
  • 26
  • There is no pointer in your code, just allocatable. Are you 100% sure you are showing the exact code that gives the error? – Vladimir F Героям слава Apr 07 '19 at 14:24
  • Yes, absolutely. I have just checked again. If you compile with flags shown, I would except you to get same error message provided that you use ifort – ATK Apr 07 '19 at 14:27
  • I just tried gfortran, and it does just give a `segmentation fault - invalid memory reference`. Again, this suggests that the call `tt = t_test( 100 )` somehow ends up in the copy assignment routine. Because when I comment out the generic assigment it works perfectly fine.# – ATK Apr 07 '19 at 14:59
  • Well of course it goes into the `copy` generic assignment. That's why you have it there, to be invoked when the `=` is in the code, don't you? – Vladimir F Героям слава Apr 07 '19 at 15:42

1 Answers1

3

The reason is that the overloaded assignment copy does not support allocatable left hand sides. So when the value of this is used in this% ii = old% ii , it actually does not exist and a null pointer is used. But I do agree the Intel's error message is confusing or even incorrect.

The automatic left hand side (re-)allocation only applies to intrisic assignments, not to user defined ones. In user-defined ones you must program yourself the exact behaviour. And you did not specify anything for not-allocated left hand sides.

This works for me:

   type T_TEST

      integer :: ii

   end type


   interface assignment(=)
     procedure copy
   end interface


   subroutine copy(this, old )

      class(t_test), allocatable, intent(out)  ::this
      type(t_test), intent(in) :: old

       if (.not.allocated(this)) allocate(this)
       this% ii = old% ii

   end subroutine

Or you can just allocate the object first (that is what I would do here because gfortran seems to not like generic resolution based on the allocatable attribute - a F08 feature).

allocate(tt)
tt = t_test( 100 )

It seems that you are thinking that just because the constructor has its result variable "marked" allocatable, it will allocate the left hand side of the assignment for you. It is not so. The only thing it does it that it allocates its own result as a temporary variable. This result is then assigned in tt = t_test() and then deallocated automatically.

Remember, the result variable is not the same as the left hand side of the assignment. The result can be used in an expression of many different types, not just in an assignment. It can be passed to a subroutine, it can be used in an arithmetic expression, it can be printed...

Your constructor can be just

   function init( size )
      integer, intent(in)                   :: size
      type(t_test)           :: init

      init% ii = size
   end function

and the result will be exactly the same. There is no reason to make it allocatable, it just complicates it, but does not change the result in the slightest.

Maybe what you are trying to follow some C++ RAII principles, but remember, C++ is simply not Fortran.

  • What I wanted was: if I say tt = t_test(100) it should act as an constructor. That is way I have the module procedure interface to init . While later if I do tt1= tt2 , that should be a copy assignment procedure. Yes, the idea is that when the LHS is allocatable it should be a constructor while not the case when it is allocated. Can you explain why the compiler decides to access the copy routine when I do tt=t_test(100). I have already defined that `t_test` should refer to the `INIT` subroutine – ATK Apr 07 '19 at 15:50
  • 1
    @A2LBK The `t_test(100)` does construct a value but it then must be **assigned** to `tt`. That's why the user defined assignment must be invoked. – Vladimir F Героям слава Apr 07 '19 at 15:53
  • @A2LBK You seem to be using C++ terminology, that is not helpful, Fortran is quite different from C++. – Vladimir F Героям слава Apr 07 '19 at 15:53
  • *"the idea is that when the LHS is allocatable it should be a constructor while not the case when it is allocated."* The Fortran standard does not support any such idea, that is just your wish. – Vladimir F Героям слава Apr 07 '19 at 15:54
  • Ahh, I understand now why it goes into the copy. Thanks! I normally did this type of constructors, as this was what many have advised when trying to do constructors in Fortran. But I see why this can easily clash. So basically it is more and less impossible to both have a constructor and copy assignment in same object – ATK Apr 07 '19 at 15:58
  • Why , you can have both completely normally. – Vladimir F Героям слава Apr 07 '19 at 16:07
  • This was the reason for my initial thread. Your answer makes sense, however, I do not see how it solves my problem. Your answer will not produce an error, because it is getting allocated in the case it not already allocated. However, it does not call my constructor. I want a way to be able to unambiguously call the constructor only, but also when doing assignment invoke the copy routine – ATK Apr 08 '19 at 11:05
  • @A2LBK How does it not call the constructor? Of course it does. I really don't get what you are after. What is an *constructor* for you? But as I said **You can just allocate the variable first**. It is extremely easy. – Vladimir F Героям слава Apr 08 '19 at 11:31
  • It does not call my function `init`, my constructor I am referring to my function `init` ? BTW: if I had changed allocatable to pointer in my module declaration, it would actually have solved the problem. Although, I would like to refrain from declaring them as pointers when I can do allocatables? – ATK Apr 08 '19 at 13:33
  • @A2BLK No, please read the updated answer. No, you won't solve anything at all with pointers. Yes, it does call init. – Vladimir F Героям слава Apr 08 '19 at 13:36
  • Thanks @Vladimir, it makes sense now! – ATK Apr 08 '19 at 13:41