Description
This is a regression from #20383. Before the patch the destructor of objects passed into a val
functions were not automatically run, but now they are. While this is a regression, I think it's actually just copying the strange(broken?) behavior of the other code. There was another issue filed about this as #20095 related to val::call
which used the optimized code that val::operator()
now uses.
I did a bit of digging and it appears that automatically destroying the object arguments was the originally intended behavior in this patch and that the user should call clone
to avoid this.
I'm still thinking about the best approach here, but my initial thought is that the user should handle explicitly deleting the object if they need to.
Output before:
>>> constructor
>>> before callback
branch [object Object]
>>> after callback
>>> destructor
After:
>>> constructor
>>> before callback
branch [object Object]
>>> destructor
>>> after callback
>>> destructor
#include <stdio.h>
#include <emscripten.h>
#include <emscripten/bind.h>
using namespace emscripten;
struct Branch {
Branch() {
printf(">>> constructor\n");
}
~Branch() {
printf(">>> destructor\n");
}
};
class Editor {
public:
void WithBranch(std::function<void(Branch*)> callback) {
Branch b;
printf(">>> before callback\n");
callback(&b); // This pointer should not be deleted!
printf(">>> after callback\n");
}
};
void EditorWithBranch(Editor& editor, val callback) {
editor.WithBranch([callback](Branch* branch) { callback(branch); });
}
int main() {
EM_ASM(
var editor = new Module.Editor();
editor.withBranch((branch) => {
console.log("branch " + branch);
});
);
}
EMSCRIPTEN_BINDINGS(xxx) {
class_<Editor>("Editor").constructor<>().function("withBranch", &EditorWithBranch);
class_<Branch>("Branch");
}