The attached project implements a Factory for two products.
The program expects an integer argument. If the argument is positive, the program creates Product 1, otherwise Product 2.
Before the program ends the Factory cleaning code is called. This deallocates the polymorphic pointer (to either Product 1 or Product 2).
My question is: Why is neither the finalizer for Product 1 nor Product 2 called?
For example, if I run the program with argument 20 I would expect to get in the console:
Instead the line in bold (Product 1: Destroying) is missing.
Am I doing something wrong?
Thank you for any suggestions.
Pointers do not automatically deallocate when the pointer goes out of scope. Try this:
program Factory ... type(Product1_t), allocatable :: prod1 type(Product2_t), allocatable :: prod2 type(Polymorphic_t), pointer :: prodX ... if(arg1 .ge. 0) then allocate(prod1) prodX => prod1 else allocate(prod2) prodX => prod2 endif call usingProd(prodX)
The finalize should be called upon exit of PROGRAM
*** However, some versions did not perform the auto-deallocation from the PROGRAM procedure, therefor, you may need to encapsulate the above in a subroutine
program Factory call Encapsulate end program subroutine Encapsulate ... type(Product1_t), allocatable :: prod1 type(Product2_t), allocatable :: prod2 type(Polymorphic_t), pointer :: prodX ... if(arg1 .ge. 0) then allocate(prod1) prodX => prod1 else allocate(prod2) prodX => prod2 endif call usingProd(prodX) end subroutine Encapsulate
I was hopping that the deallocation of the pointer would automatically result in the destruction of the object.
In your example, I can see that the two targets prod1 and prod2 would eventually go out of scope and get destroyed because they are unsaved.
>> I can see that the two targets prod1 and prod2 ...
Thanks for correcting my omission of target on the allocatables. Pointers in C++ do not call the dtor when it goes out of scope, Fortran is no different. It is the programmer's responsibility to manage the lifetime of these (pointer allocated) objects.
Also, it doesn't make sense to deallocate a pointee as compiler/runtime cannot ascertain if the pointee has no remaining references (Fortran does not maintain reference counters). Caution about lifetimes, in the second snip, should the prodX pointer reside in a module, and the prod1&2 reside in the subroutine, reference of prodX after return from subroutine Encapsulate is undefined (due to in this case of the pointee being deallocated but the pointer not being nullified).
Sure Jim. Fortran does not have garbage collection, so no reference counters are present. Thank you for the advice on the actual scope of the variables. I think I was not sufficiently clear in my original post.
In my example, I went for an OO approach to defining the factory. Specifically, the factory class has the polymorphic product (must be a pointer) as a field/property and two type bound procedures for handling the creation and clean-up:
All in all, there is a unnamed object somewhere which cannot be reached anymore.
My question is: Is this a programmer's error? What have I done wrong?
Thank you for your insight into this.
Are you using a current compiler?
>dir *.f90 /b | ff08depends - > compile-order.txt >ifort /check:all /warn:all /standard-semantics /Fefactory-test.exe @compile-order.txt ifort /warn:all /standard-semantics /Fefactory-test.exe abstract.f90 product1.f90 product2.f90 factory.f90 main.f90 Intel(R) Visual Fortran Intel(R) 64 Compiler for applications running on Intel(R) 64, Version 17.0 Build 20161005 Copyright (C) 1985-2016 Intel Corporation. All rights reserved. product1.f90(30): remark #7712: This variable has not been used. [THIS] subroutine execute_sub(this) ---------------------------^ product1.f90(20): remark #7712: This variable has not been used. [THIS] subroutine clean(this) ---------------------^ product2.f90(30): remark #7712: This variable has not been used. [THIS] subroutine execute_sub(this) ---------------------------^ product2.f90(20): remark #7712: This variable has not been used. [THIS] subroutine clean(this) ---------------------^ Microsoft (R) Incremental Linker Version 14.00.24215.1 Copyright (C) Microsoft Corporation. All rights reserved. -out:factory-test.exe -subsystem:console abstract.obj product1.obj product2.obj factory.obj main.obj >factory-test.exe 1 Factory: Creating Product 1. Factory: Creation success. Product 1: Using. Product 1: Destroying. Factory: Destroying product success.
You are definitely are getting what I was expecting. I think you may be on to something, because I use
Compiling with Intel(R) Visual Fortran Compiler XE 220.127.116.118 [IA-32]...
Could I ask you to build and run with the IA-32 (your version)?
Please let me know what you get.
Thank you for your help.
Full 2003 support is only 16.0 onwards and there have been many bug fixes since. I think you will find many other oo problems with XE 18.104.22.1688 [IA-32]... you really need to upgrade.