I am having an issue passing sol::table around from Lua, to C++, and then back to Lua.
Here is a minimal example that reproduces the issue I am facing:
The C++ code:
#include <iostream>
#include <string>
#include <sol2/sol.hpp>
void test_function(sol::table properties) {
std::cout << "Inside: test_function" << std::endl;
std::string text = properties["text"];
std::cout << "The text is: " << text << std::endl;
std::cout << "The number is: " << static_cast<int>(properties["number"]) << std::endl;
sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::math, sol::lib::string, sol::lib::io);
lua.script_file("test_script.lua");
sol::function second_func = lua["second_func"];
second_func(properties);
}
int main(int argc, char** argv) {
sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::math, sol::lib::string, sol::lib::io);
lua.set_function("test_function", test_function);
lua.script_file("test_script.lua");
sol::function first_func = lua["first_func"];
first_func();
return 0;
}
The Lua script:
function first_func()
print('Inside: first_func')
properties = {}
properties['text'] = 'blarg'
properties['number'] = 8
test_function(properties)
end
function second_func(properties)
print('Inside: second_func')
print('The text is:', properties['text'])
print('The number is:', properties['number'])
end
Here is the output when I run the program:
> ./sol_test
Inside: first_func
Inside: test_function
The text is: blarg
The number is: 8
Inside: second_func
terminate called after throwing an instance of 'sol::error'
what(): lua: error: lua: error: test_script.lua:14: attempt to index a nil value (local 'properties')
Aborted
Is this expected behavior? I would think the sol::table should be copied from Lua to C++, and then be copied back into Lua from C++.
Let me know if you need more information to debug this. Thanks. :slightly_smiling_face:
The first sol::table comes from a different Lua state. You can't transfer tables between states. You have 2 lua states in your code: one in the main, one in the first_func. Each sol::state is its own lua_State*, and each contains its own references and memory that cannot be mixed unless you specifically invoke the Lua C API calls to switch between states / threads.
If you need to access the same Lua state, please use sol::this_state: docs here. Here's your example, using it:
````cpp
void test_function(sol::table properties, sol::this_state ts) {
std::cout << "Inside: test_function" << std::endl;
// get a view into a previously-made lua state
sol::state_view lua = ts;
// now this will work
// because you're getting the same table here
// and not some weird table "properties" that doesn't actually exist
// in some new lua state you're freshly allocating
sol::function second_func = lua["second_func"];
second_func(properties);
}
int main(int argc, char** argv) {
sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::math, sol::lib::string, sol::lib::io);
lua.set_function("test_function", test_function);
lua.script_file("test_script.lua");
sol::function first_func = lua["first_func"];
first_func();
return 0;
}
````
And it works exactly as you'd expect.
Most helpful comment
The first
sol::tablecomes from a different Lua state. You can't transfer tables between states. You have 2 lua states in your code: one in the main, one in thefirst_func. Eachsol::stateis its ownlua_State*, and each contains its own references and memory that cannot be mixed unless you specifically invoke the Lua C API calls to switch between states / threads.If you need to access the same Lua state, please use
sol::this_state: docs here. Here's your example, using it:````cpp
include
include
void test_function(sol::table properties, sol::this_state ts) {
std::cout << "Inside: test_function" << std::endl;
}
int main(int argc, char** argv) {
sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::math, sol::lib::string, sol::lib::io);
}
````
And it works exactly as you'd expect.