I’ve created a minimum working example of my problem:
foo.h:
#ifndef FOO_H_
#define FOO_H_
#include "ISO_Fortran_binding.h"
#ifdef __cplusplus
extern "C" {
#endif
struct CPP_UsesFortranArray;
typedef struct CPP_UsesFortranArray CPP_UsesFortranArray_t;
void C_UsesFortranArray_init(
CPP_UsesFortranArray_t **ptr,
const CFI_cdesc_t *array);
double C_UsesFortranArray_maxval(const CPP_UsesFortranArray_t *ptr);
void print_array_and_maxval(const CFI_cdesc_t *array);
#ifdef __cplusplus
}
#endif
#endif // FOO_H_
I followed your advice with the double pointer and the constructor works even though I am not 100 % sure why. 
foo.cpp:
#include "foo.h"
#include <iostream>
#include <cmath>
template <typename T>
struct FortranArray {
typedef T real_t;
// A const reference to rank 1 Fortran array
// (can be discontiguous but with regular strides)
const CFI_cdesc_t *obj;
// Constructor
FortranArray(const CFI_cdesc_t *obj_) : obj(obj_) {
std::cout << "In FortranArray Constructor: " << std::endl;
for (size_t i = 0; i < this->size(); i++) {
std::cout << "obj[" << i <<"] = " << this->operator()(i) << std::endl;
}
}
// Returns the i'th element of the vector
inline T operator()(const size_t i) const {
char *elt = (char *) obj->base_addr;
elt += (i*obj->dim[0].sm);
return *(T *) elt;
}
inline size_t size() const {
return obj->dim[0].extent;
}
};
template <typename ArrayType>
class UsesFortranArray {
const ArrayType &array; // Reference to a Fortran array
typedef typename ArrayType::real_t real_t;
public:
// Constructor
UsesFortranArray(const ArrayType &inputArray) :
array(inputArray) {
std::cout << "In UsesFortranArray Constructor" << std::endl;
this->maxval();
}
real_t maxval() {
real_t res = array(0);
for (size_t i = 1; i < array.size(); i++) {
if (array(i) > res) res = array(i);
}
std::cout << "maxval(array) = " << res << std::endl;
return res;
}
};
extern "C" {
typedef FortranArray<double> Vector;
typedef UsesFortranArray<Vector> UsesVector;
void print_array_and_maxval(const CFI_cdesc_t *array) {
// Array is printed in the constructor of FortranArray
Vector a(array);
// maxval is printed in constructor of UsesVector
UsesVector use_f(a);
}
struct CPP_UsesFortranArray {
void *obj; // Cast of UsesFortranArray<>
};
void C_UsesFortranArray_init(
CPP_UsesFortranArray_t **ptr,
const CFI_cdesc_t *array) {
// Return if *ptr is not NULL
if (*ptr != NULL) {
std::cout << "ptr is not NULL" << std::endl;
return;
}
CPP_UsesFortranArray_t *init_ptr;
init_ptr = (typeof(init_ptr)) malloc(sizeof(*init_ptr));
UsesVector *obj = new UsesVector(Vector(array));
init_ptr->obj = obj;
*ptr = init_ptr;
}
double C_UsesFortranArray_maxval(const CPP_UsesFortranArray_t *ptr) {
if (ptr == NULL) return static_cast<double>(1.0/0.0);
std::cout << "in C_UsesFortranArray_maxval\n";
UsesVector *obj = static_cast<UsesVector *>((ptr)->obj);
return obj->maxval();
}
} // extern "C"
Now for the Fortran driver main_foo.f90:
module foo_interface
use, intrinsic :: iso_c_binding, only: c_double, c_ptr, c_null_ptr
implicit none
interface
! void print_array_and_maxval(const CFI_cdesc_t *array)
subroutine print_array_and_maxval(A) &
bind(c,name="print_array_and_maxval")
import c_double
real(c_double), intent(in) :: A(:)
end subroutine
! void C_UsesFortranArray_init(
! CPP_UsesFortranArray_t **ptr,
! const CFI_cdesc_t *array);
subroutine C_UsesFortranArray_init(ptr,array) &
bind(c,name="C_UsesFortranArray_init")
import c_ptr, c_double
type(c_ptr), intent(out) :: ptr
real(c_double), intent(in) :: array(:)
end subroutine
! double C_UsesFortranArray_maxval(CPP_UsesFortranArray_t *ptr);
real(c_double) function C_UsesFortranArray_maxval(ptr) &
bind(c,name="C_UsesFortranArray_maxval")
import c_ptr, c_double
type(c_ptr), intent(in), value :: ptr
end function
end interface
end module
program main_foo
use, intrinsic :: iso_c_binding
use foo_interface
implicit none
real(c_double) :: A(5)
type(c_ptr) :: cpp_obj = c_null_ptr
A = [1,2,3,4,5]
write(*,*) "--------------------"
write(*,*) "Calling print_array_and_maxval"
call print_array_and_maxval(A)
write(*,*) "--------------------"
write(*,*) "Before calling constructor:"
write(*,*) " associated(cpp_obj) = ", c_associated(cpp_obj)
call C_UsesFortranArray_init(cpp_obj,A)
write(*,*) "After calling constructor:"
write(*,*) " associated(cpp_obj) = ", c_associated(cpp_obj)
write(*,*) "maxval in Fortran", maxval(A)
! Something goes wrong in this call
write(*,*) "maxval in C++ ", C_UsesFortranArray_maxval(cpp_obj)
end program
Output:
~/fortran/mwe$ g++ -I./ -Wall foo.cpp -c
~/fortran/mwe$ gfortran foo.o main_foo.f90 -o main_foo -lstdc++
~/fortran/mwe$ ./main_foo
--------------------
Calling print_array_and_maxval
In FortranArray Constructor:
obj[0] = 1
obj[1] = 2
obj[2] = 3
obj[3] = 4
obj[4] = 5
In UsesFortranArray Constructor
maxval(array) = 5
--------------------
Before calling constructor:
associated(cpp_obj) = F
In FortranArray Constructor:
obj[0] = 1
obj[1] = 2
obj[2] = 3
obj[3] = 4
obj[4] = 5
In UsesFortranArray Constructor
maxval(array) = 5
After calling constructor:
associated(cpp_obj) = T
maxval in Fortran 5.0000000000000000
in C_UsesFortranArray_maxval
Program received signal SIGSEGV: Segmentation fault - invalid memory reference.
Backtrace for this error:
#0 0x7f526073ab2a
#1 0x7f5260739d25
#2 0x7f526015103f
#3 0x555d0eab435c
#4 0x555d0eab428a
#5 0x555d0eab40a9
#6 0x555d0eab49b2
#7 0x555d0eab4a1c
#8 0x7f5260133bf6
#9 0x555d0eab3e59
#10 0xffffffffffffffff
Segmentation fault (core dumped)
The segfault appears to originate in foo.cpp in the maxval() function inside of UsesFortranArray when attempting to retrieve the value array(0).