With CxxWrap, method cannot return an usable complex number

Hi,

I am trying to use CxxWrap to wrap a C++ library. I am wrapping a type that has a method that returns a std::complex. I have also wrapped the std::complex type, since it is not already in the CxxWrap library.

The problem comes when I try to use this method. The complex number is instantly deleted, and the cpp_object of the returned object is the null pointer.

Everything seems to work when I do a normal function (not a wrapped object method) that returns a complex number. The pointer to the complex number is not null, however if I try to access it (e.g. via the std::complex<double>::real function) it gives a segmentation fault.

I tried to do a minimal working example

// format
#include <fmt/format.h>

// julia CXX Wrapper
#include <jlcxx/jlcxx.hpp>
#include <jlcxx/stl.hpp>

// std
#include <complex>
#include <random>
#include <vector>

template <typename T> class Vettore {
public:
  using value_type = T;

  Vettore(std::vector<T> re, std::vector<T> im)
      : real_(std::move(re)), imag_(std::move(im)) {}

  auto Get(std::size_t idx) const -> std::complex<T> {
    fmt::print("returning v[{}]: {} + im {}\n", idx, real_[idx], imag_[idx]);
    return {real_[idx], imag_[idx]};
  };

private:
  std::vector<T> real_{};
  std::vector<T> imag_{};
};

struct WrapStdComplex {
  template <typename TypeWrapperT> void operator()(TypeWrapperT &&wrapped) {
    typedef typename TypeWrapperT::type WrappedT;
    typedef typename WrappedT::value_type T;
    wrapped.template constructor<T const &, T const &>();
    wrapped.method("real", [](WrappedT const &x) {
      fmt::print("returning the real part of x: {} + im {}\n", x.real(),
                 x.imag());
      return x.real();
    });
    wrapped.method("imag", [](WrappedT const &x) { return x.imag(); });
  }
};

struct WrapVettore {
  template <typename TypeWrapperT> void operator()(TypeWrapperT &&wrapped) {
    typedef typename TypeWrapperT::type WrappedT;
    typedef typename WrappedT::value_type T;
    wrapped.template constructor<std::vector<T>, std::vector<T>>();
    wrapped.method("Get", &WrappedT::Get);
  }
};

namespace jlcxx {} // namespace jlcxx

JLCXX_MODULE
define_julia_module(jlcxx::Module &mod) {
  using namespace jlcxx;

  mod.add_type<Parametric<TypeVar<1>>>("StdComplex")
      .apply<std::complex<float>, std::complex<double>>(WrapStdComplex());

  mod.method("test_complex_return", []() {
    auto x = std::complex<double>(1.5, 2.3);
    fmt::print("x: {} + im {}\n", x.real(), x.imag());
    return x;
  });

  mod.add_type<Parametric<TypeVar<1>>>("Vettore").apply<Vettore<double>>(
      WrapVettore());

  mod.method(
      "test_complex_return",
      [](Vettore<double> const &v, std::size_t idx) -> std::complex<double> {
        return v.Get(idx);
      });
}

// vim: set ft=cpp ts=2 sts=2 et sw=2 tw=80: //
  • x = mymodule.test_complex_return() returns a proper object / pointer to something but segfaults if I do mymodule.real(x),
  • v = mymodule.Vettore(StdVector(rand(10)), StdVector(rand(10))) and then mymodule.Get(v, 0) returns a mymodule.StdComplexAllocated{Float64}(Ptr{Nothing} @0x0000000000000000)

Seems that the object returned is instantly deleted. The print statements in the C++ code work without issues.

Any suggestion on how to debug it or solve it? Probably I am using the library in a bad way. The Julia module is the default one shown in the CxxWrap documentation / homepage I didn’t add anything inside.