Hi
I think I must be doing something obviously wrong here, but embind seems to make temporary copies of C++ objects for reasons I don't understand.
Here's an example. JS code calling a C++ function that then calls back to JS.
em++ Simple.cpp --bind -o Simple.html --post-js test.js
Simple.cpp:
// em++ Simple.cpp --bind -o Simple.html --post-js test.js
#include <emscripten/bind.h>
#include <emscripten/val.h>
#include <emscripten/emscripten.h>
#include <cstdio>
#include <memory>
class Test1
{
public:
Test1() :
m_int(123)
{
printf("%s ctor %p\n", __FUNCTION__, this);
}
Test1(const Test1 &rhs) :
m_int(rhs.m_int)
{
printf("%s copy ctor %p\n", __FUNCTION__, this);
}
~Test1()
{
printf("%s dtor %p\n", __FUNCTION__, this);
}
int m_int;
};
class Test2
{
public:
Test2()
{
printf("%s ctor %p\n", __FUNCTION__, this);
}
Test2(const Test2 &rhs) :
m_test1(rhs.m_test1)
{
printf("%s copy ctor %p\n", __FUNCTION__, this);
}
~Test2()
{
printf("%s dtor %p\n", __FUNCTION__, this);
}
int m_pad; // Just to get this != &this->m_test1
Test1 m_test1;
};
Test2 g_test2;
void InvokeJs(emscripten::val callback)
{
printf("In C++ function %s, calling back to JS\n", __FUNCTION__);
callback(g_test2);
}
EMSCRIPTEN_BINDINGS(Main)
{
using namespace emscripten;
function("invokeJs", &InvokeJs);
value_object<Test1>("Test1")
.field("int", &Test1::m_int)
;
value_object<Test2>("Test2")
.field("test1", &Test2::m_test1)
;
}
void MainLoop()
{
}
int main(int argc, char *argv[])
{
emscripten_set_main_loop(&MainLoop, 0, 1);
return 0;
}
test.js:
function myInit() {
var button = document.createElement("BUTTON");
button.appendChild(document.createTextNode("Call C++"));
button.onclick = function () {
var myCallback = function (test2) {
Module.print("In JS callback. test2.test1.int = ", test2.test1.int);
// HACK for testing both value_object and class_ bindings.
if (test2.hasOwnProperty("delete")) {
test2.delete();
}
}
Module.print("\nIn JS, calling C++ function");
Module.invokeJs(myCallback);
if (typeof Module.invokeJsRef === "function") {
Module.print("\nIn JS, calling C++ function using refs");
Module.invokeJsRef(myCallback);
}
Module.print("Done");
};
document.body.insertBefore(button, document.getElementById("canvas").parentElement);
}
myInit();
Hitting "Call C++" button gives:
Test1 ctor 0x16f4
Test2 ctor 0x16f0
In JS, calling C++ function
In C++ function InvokeJs, calling back to JS
Test1 copy ctor 0x501f14
Test2 copy ctor 0x501f10
Test1 copy ctor 0x501f20
~Test1 dtor 0x501f20
~Test2 dtor 0x501f10
~Test1 dtor 0x501f14
In JS callback. test2.test1.int = 123
Done
These temporaries are destroyed before even making it in to the JS code, so it seems like they c/should be elided?
I have worked around this by wrapping non-trivial types in a reference_wrapper-like type. Attached as Ref.cpp. I only need read-only access so the write side of things isn't covered, but it just seems like I'm missing something obvious here...
Thanks for any help!
Luke.