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 domymodule.real(x)
, -
v = mymodule.Vettore(StdVector(rand(10)), StdVector(rand(10)))
and thenmymodule.Get(v, 0)
returns amymodule.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.