Pointer modification with CxxWrap.jl

Using CxxWrap.jl, I am trying to send a pointer to struct to C++ functions, which will modify the values inside. I did small experiments.

C++ side:

#include "jlcxx/jlcxx.hpp"

struct Point{
  float x, y;
};

Point* move(Point* a, int amount) { 
    a->x += amount; 
    a->y += amount; 
    return a; 
}

void test() {
  Point a;
  a.x = 1.0f;
  a.y = 2.0f;

  Point* b;
  b = move(&a, 100);

  printf("[test] a = %f, %f\n", a.x, a.y);
  printf("[test] b = %f, %f\n", b->x, b->y);
}

JLCXX_MODULE define_julia_module(jlcxx::Module& mod)
{
  mod.map_type<Point>("Point");
  mod.method("move", move);
  mod.method("test", test);
}

The move() function was intended as a void type, but it returns the pointer for this experiment.

Julia side:

module MyTypes
    using CxxWrap
    using Test

    struct Point
        x :: Float32
        y :: Float32
    end

    @wrapmodule joinpath(@__DIR__, "lib", "libmytypes")

    function __init__()
        @initcxx
    end
end

Experiment 1

MyTypes.test()

The output is

[test] a = 101.000000, 102.000000
[test] b = 101.000000, 102.000000

Both a and b changed, as intended.

Experiment 2
When I pass a struct from Julia, I see a did NOT change, but b changed.

a = MyTypes.Point(1.0, 2.0)
b = MyTypes.move(Ref(a), 100)
bb = unsafe_load(b)
@show a.x, a.y
@show bb.x, bb.y

Output:

(a.x, a.y) = (1.0f0, 2.0f0)
(bb.x, bb.y) = (101.0f0, 102.0f0)

Experiment 3
If I pass an array of struct, instead of Ref(a), then both values changed.

c = [a]
d = MyTypes.move(c, 100)
@show c[1].x, c[1].y
dd = unsafe_load(d)
@show dd.x, dd.y

Output:

((c[1]).x, (c[1]).y) = (101.0f0, 102.0f0)
(dd.x, dd.y) = (101.0f0, 102.0f0)

Why doesn’t Experiment 2 change the values in a? Shouldn’t it change the values in a?

I realized that I made the Julia struct immutable. After changing it mutable, in Experiment 2, I changed Ref(a) to pointer_from_objref(a), which changed both a and b.

With the mutable struct, Experiment 3 produced a segmentation fault error.

1 Like