Home > Software engineering >  BindingError: Passing raw pointer to smart pointer is illegal
BindingError: Passing raw pointer to smart pointer is illegal

Time:10-15

Consider the following C code and corresponding Emscripten bindings.

class IBar {
    void qux() = 0;
};

struct BarWrapper : public wrapper<IBar> {
    void qux() override {
        return call<>("qux");
    }
}

EMSCRIPTEN_BINDINGS(IBar) {
    class_<IBar>("IBar")
        .smart_ptr<std::shared_ptr<IBar>>("IBar")
        .function("qux", &IBar::qux)
        .allow_subclass<BarWrapper>("BarWrapper");;
}

class Foo {
    std::shared_ptr<IBar> getBar() const;
    void setBar(std::shared_ptr<IBar> bar);
};

EMSCRIPTEN_BINDINGS(Foo) {
    class_<Options>("Foo")
        .constructor<>()
        .property("bar", &Foo::getBar, &Foo::setBar);
}

In TypeScript, I have the following:

class Bar {
    qux() {

    }
}

const bar = new Module.Bar.implement(new Bar())

The issue here is that Foo::setBar takes a std::shared_ptr but Module.Bar.implement returns a raw pointer. That prevents me from passing bar to Foo::setBar.

Is anyone aware of how to convert a raw pointer to a shared pointer here? Alternatively, is anyone aware of a good workaround?

CodePudding user response:

While OP did mention in the comments that they'd rather not go down that road, for the sake of completeness:

Adding an overload/alternative to setBar() that takes a raw pointer:

class Foo {
    std::shared_ptr<IBar> getBar() const;
    void setBar(std::shared_ptr<IBar> bar);
    void setBarTakingOwnership(IBar* b) { setBar(std::shared_ptr<IBar>(b)); }
};

And using it when binding:

EMSCRIPTEN_BINDINGS(Foo) {
    class_<Options>("Foo")
        .constructor<>()
        .property("bar", &Foo::getBar, &Foo::setBarTakingOwnership);
}

Should do the trick.

N.B. As mentioned in the comments, taking ownership of a raw pointer is always thin-ice territory, so if you HAVE to take ownership of a raw pointer, it's better to be very clear in the method name.

CodePudding user response:

I figured out a solution that doesn't return adding a method that accepts a raw pointer.

It works by expanding the bindings for IBar.

EMSCRIPTEN_BINDINGS(IBar) {
    class_<IBar>("IBar")
        .smart_ptr<std::shared_ptr<IBar>>("IBar")
        .function("qux", &IBar::qux)
        .allow_subclass<BarWrapper, std::shared_ptr<BarWrapper>>("BarWrapper", "BarWrapperSharedPtr");;
}
  • Related