javascriptemscriptenembind

Working with Embind, does a returned ClassHandle.delete() properly delete all the properties?


If emscripten/embind returns an object with a bunch of vector properties, do I need to call .delete() on each property, or can I just call .delete() on the returned object?

ie: If I am returned an emscripten ClassHandle for RGB, do I need to call rgb.r.delete(), or does rgb.delete() handle that for me?

#include <emscripten/bind.h>
using namespace emscripten;

class RGB {
public:
    std::vector<unsigned char> r;
    std::vector<unsigned char> g;
    std::vector<unsigned char> b;
    RGB (
        std::vector<unsigned char> r_ = std::vector<unsigned char>(0,0),
        std::vector<unsigned char> g_ = std::vector<unsigned char>(0,0),
        std::vector<unsigned char> b_ = std::vector<unsigned char>(0,0)
        ) {
        r = r_;
        g = g_;
        b = b_;
    }
};

EMSCRIPTEN_BINDINGS(my_module) {
    class_<RGB>("RGB")
        .constructor<
            std::vector<unsigned char>,
            std::vector<unsigned char>,
            std::vector<unsigned char>
            >()
        .property("r", &RGB::r)
        .property("g", &RGB::g)
        .property("b", &RGB::b)
        ;
    register_vector<unsigned char>("Uint8Array");
}

Solution

  • According to Emscripten documentation Memory Management

    Warning

    It is strongly recommended that JavaScript code explicitly deletes any C++ object handles it has received.

    The delete() JavaScript method is provided to manually signal that a C++ object is no longer needed and can be deleted:

    var x = new Module.MyClass; x.method(); x.delete();

    var y = Module.myFunctionThatReturnsClassInstance(); y.method(); y.delete();

    Note

    Both C++ objects constructed from the JavaScript side as well as those returned from C++ methods must be explicitly deleted.

    var myclass = new Module.MyClass(); //Creates a C++ object from JS.
    myclass.delete(); // Calls ~MyClass destructor in C++.
    
    var myclass = Module.MyClass.CreateInstance(); //Creates a C++ object from C++ and returns to JS.
    myclass.delete(); // Calls ~MyClass destructor in C++.
    

    In C++

    Your class is responsible for any internal dynamic memory created(using new operator). Dynamic memory created needs to be deleted in destructor. In your provided example you don't use dynamic memory, no need to delete any memory or create destructor.

    The 3 std::vector (r,g and b) are created with the stack memory(no dynamic memory using new operator).

    I suggest that your class the attributes need to be private and have getters to prevent external access.

    class RGB {
    private:
        std::vector<unsigned char> r;
        std::vector<unsigned char> g;
        std::vector<unsigned char> b;
    
    public:
        RGB(const std::vector<unsigned char>& r_ = {}, 
            const std::vector<unsigned char>& g_ = {},
            const std::vector<unsigned char>& b_ = {})
            : r(r_), g(g_), b(b_)
        {
        }
        
        const std::vector<unsigned char>& getR() const {
            return r;
        }
        
        const std::vector<unsigned char>& getG() const {
            return g;
        }
        
        const std::vector<unsigned char>& getB() const {
            return b;
        }
    };