Передайте указатель на std::vector в Javascript, используя Emscripten, и используйте его

Я хотел бы создать std::vector (в частности, std::vector<string>) на С++, а затем передать его (точнее, указатель на него) в Javascript, чтобы иметь доступ к его данным/функциям из непосредственно написанного Javascript.

Пока я могу получить целочисленный указатель:

vector<string> myVector;
myVector.push_back("First item");
myVector.push_back("Second item");

EM_ASM_ARGS({
  // Prints out an integer value of the pointer,
  // but I would like to access the object members/data 
  // of myVector
  console.log($0);
}, &myVector);

Я нашел информацию по адресу http://kripken.github.io/emscripten-site/docs/api_reference/bind.h.html#register_vector__cCP и http://kripken.github.io/emscripten-site/docs/porting/connecting_cpp_and_javascript/embind.html#built-in-type-conversions о функции register_vector

#include <emscripten/bind.h>
EMSCRIPTEN_BINDINGS(Wrappers) {
  register_vector<std::string>("VectorString");
};

который можно использовать для создания нового вектора из мира Javascript:

var myVector = new Module.VectorString();

но я не могу понять, как использовать это для доступа к вектору, который уже существует в мире С++.

Если я попытаюсь использовать Module.Runtime.dynCall('v', $0, []); для указателя, как в https://stackoverflow.com/a/29319440/1319998, когда передавая указатели на функции, я получаю сообщение об ошибке:

Invalid function pointer '380' called with signature 'v'

Я пробовал несколько разных комбинаций сигнатур, и все они, похоже, терпят неудачу (что меня не очень удивляет: на самом деле я вызываю не указатель функции, а указатель на экземпляр объекта)


person Michal Charemza    schedule 29.03.2015    source источник
comment
Я отредактировал этот вопрос, чтобы объяснить, почему он не является дубликатом stackoverflow.com/a/29319440/1319998 . В этом случае решение не применяется: это вызов указателя функции С++ из Javascript, а этот вопрос касается доступа к членам существующего объекта С++.   -  person Michal Charemza    schedule 29.03.2015
comment
Я также отредактировал заголовок на stackoverflow.com/a/29319440/1319998 (это мой вопрос) на надеюсь, лучше показать, почему это отличается.   -  person Michal Charemza    schedule 29.03.2015


Ответы (1)


Используя трюк reinterpret_cast из https://stackoverflow.com/a/27364643/1319998, вы можете добавить к объекту еще один конструктор возвращается из фабрики register_vector, которая ничего не делает, кроме преобразования целочисленного указателя в vector<string>:

vector<string> *vectorFromIntPointer(uintptr_t vec) {
  return reinterpret_cast<vector<string> *>(vec);
}

EMSCRIPTEN_BINDINGS(Wrappers) {
  register_vector<string>("VectorString").constructor(&vectorFromIntPointer, allow_raw_pointers());
};

Затем, если вы создаете вектор в коде C++, вы можете получить доступ к коду JS с помощью

  • Получение указателя на него
  • Передача указателя на JS-код через EM_AMS_ARGS
  • В коде JS создайте новый объект Module.VectorString, передав значение указателя конструктору.

Как в следующем коде:

vector<string> myVector;
myVector.push_back("First item");
myVector.push_back("Second item");

EM_ASM_ARGS({
  var myVector = new Module.VectorString($0);
  // Prints "Second item"
  console.log(myVector.get(1));
}, &myVector);
person Michal Charemza    schedule 29.03.2015
comment
Где документация для функции .get? Как вы нашли эту функцию get для myVector? Пожалуйста, киньте ссылку, спасибо. - person Buddhika Chaturanga; 05.04.2017