Передать по значению
Я предлагаю вам передать name
в качестве аргумента setup
и callHello
. Это решает проблему с временем жизни объектов.
N.B.: Вызов функции Lua из C ++, которая затем вызывает функцию C ++ из Lua, кажется очень неэффективным. Вы уверены в своем дизайне? Вам действительно нужна эта дополнительная косвенность через Lua?
bindings.h
#pragma once
#include <iostream>
#include <string>
class Test {
public:
void callHello(std::string const &name, lua_State *L) {
lua_getglobal(L, "hello");
lua_pushstring(L, name.c_str());
if (lua_pcall(L, 1, 0, 0) != 0) {
std::cout << "failed to call hello function\n"
<< lua_tostring(L, -1) << '\n';
return;
}
}
};
test.cpp
#include <iostream>
#include <string>
#include <lua.hpp>
extern "C" int luaopen_my(lua_State *L);
class myLua {
public:
myLua(std::string const &name) {
lua_State *L = luaL_newstate();
luaL_openlibs(L);
luaopen_my(L);
const char *script = "function setup(name)\n"
" local test = my.Test()\n"
" test:callHello(name)\n"
"end\n"
"function hello(name)\n"
" print('hello is called by : ' .. name)"
"end";
if (luaL_dostring(L, script) != 0) {
std::cout << "failed to run lua script\n"
<< lua_tostring(L, -1) << '\n';
lua_close(L);
return;
}
lua_getglobal(L, "setup");
lua_pushstring(L, name.c_str());
if (lua_pcall(L, 1, 0, 0) != 0) {
std::cout << "failed to call setup function\n"
<< lua_tostring(L, -1) << '\n';
lua_close(L);
return;
}
lua_close(L);
}
};
int main() {
myLua lua1("Apple");
myLua lua2("Orange");
}
Проход по lightuserdata
Как вы и просили, вы можете также вставить указатель на строку в виде lightuserdata в реестр и извлечь ее в функции callHello
. Использование реестра опасно по разным причинам. Ключи могут столкнуться, и вы должны быть абсолютно уверены, что ключ не использовался в другом месте. Указатели на данные C ++ могут зависнуть, а Lua не знает и не может знать об этом и с радостью выдаст вам неверный указатель. Разыменование приводит к трудно отлаживаемой ошибке сегментации.
N.B.: Я считаю, что это плохой дизайн и его следует избегать. Отказ от безопасности памяти для удобства отсутствия передачи параметра не выглядит хорошим компромиссом.
bindings.h
#pragma once
#include <iostream>
#include <string>
class Test {
public:
void callHello(lua_State *L) {
// Fetch light userdata from the registry with key "name" and
// pray that it is there
lua_pushstring(L, "name");
lua_gettable(L, LUA_REGISTRYINDEX);
std::string name;
if (lua_islightuserdata(L, -1) == 1) {
name = *static_cast<std::string *>(lua_touserdata(L, -1));
lua_pop(L, 1);
} else {
lua_pushstring(L, "userdata corrupted or absent");
lua_error(L);
return;
}
// Call hello function with fetched name
lua_getglobal(L, "hello");
lua_pushstring(L, name.c_str());
if (lua_pcall(L, 1, 0, 0) != 0) {
std::cout << "failed to call hello function\n"
<< lua_tostring(L, -1) << '\n';
return;
}
}
};
test.cpp
#include <iostream>
#include <string>
#include <lua.hpp>
extern "C" int luaopen_my(lua_State *L);
class myLua {
public:
myLua(std::string name) {
lua_State *L = luaL_newstate();
luaL_openlibs(L);
luaopen_my(L);
const char *script = "function setup()\n"
" local test = my.Test()\n"
" test:callHello()\n"
"end\n"
"function hello(name)\n"
" print('hello is called by : ' .. name)"
"end";
if (luaL_dostring(L, script) != 0) {
std::cout << "failed to run lua script\n"
<< lua_tostring(L, -1) << '\n';
lua_close(L);
return;
}
// Push light userdata into the registry with key "name"
lua_pushstring(L, "name");
lua_pushlightuserdata(L, static_cast<void *>(&name));
lua_settable(L, LUA_REGISTRYINDEX);
lua_getglobal(L, "setup");
if (lua_pcall(L, 0, 0, 0) != 0) {
std::cout << "failed to call setup function\n"
<< lua_tostring(L, -1) << '\n';
lua_close(L);
return;
}
lua_close(L);
}
};
int main() {
myLua lua1("Apple");
myLua lua2("Orange");
}
Общие биты
Файл интерфейса SWIG не нуждается в адаптации и остается тем же в любом случае.
my.i
%module my
%{
#include "bindings.h"
%}
%include <std_string.i>
%include <typemaps.i>
%typemap(default) (lua_State *L)
{
$1 = L;
}
%include "bindings.h"
Компиляция и запуск могут быть выполнены для обоих случаев с помощью (например)
$ swig -lua -c++ my.i
$ clang++ -Wall -Wextra -Wpedantic -I/usr/include/lua5.2/ my_wrap.cxx test.cpp -llua5.2
$ ./a.out
hello is called by : Apple
hello is called by : Orange