I''ve been using Lua lately and have been exporting C/C++ functions using the toLua glue (and heavily modifying it). I was more than curious to see if I could get a little STL action going along with it. I don''t know how many of you are familiar with Lua, but it''s actually more of an STL problem. The toLua code does something simliar to this (forgive me if they api isn''t EXACTly as it should be, but you should get the idea):
int tolua_ObjectType_new(lua_State* Machine)
{
ObjectType* self = new ObjectType();
tolua_pushusertype(Machine,(void*)self);
}
int tolua_ObjectType_delete(lua_State* Machine)
{
ObjectType* self = tolua_tousertype(Machine,1,0);
delete self;
}
What I wanted to do was put new objects into an STL container, and put an iterator as the userdata. This way the objects created with Lua would be visible to my program (basically so that I could perform update procedures within the main loop without exposing the loop to the Lua script). My method worked something like this:
list<objectType> Objects;
int tolua_ObjectType_new(lua_State* Machine)
{
Objects.push_back(ObjectType());
tolua_pushusertype(Machine, (void*)Objects.back());
}
int tolua_ObjectType_delete(lua_State* Machine)
{
list<objectType>::iterator iterObject = tolua_tousertype(Machine,1,0);
Objects.erase(iterObject);
}
I don''t know about you, but I thought that this was pretty cool. Unfortunately there are several problems. The first: from what I read in the STL documents, "back()" returns a reference, not a pointer (even though I could replace this with "--end()").
You could argue that an iterator will lose it''s place once more objects are inserted and removed from the container, but technically this isn''t the behaviour of a list because list containers always occupy the same space in memory (it specifically states this about the list container in the docs).
The BIG problem is that STL doesn''t allow you to arbitrarily cast an iterator into a void pointer. I just need to store the iterator somehow, but this won''t compile (and yes, I know in this example I didn''t cast it, but even when you do it will generate compile errors). I''ve thought of several ways around this, but I thought I would get more opinions before I continue.
1) I could use a map and then generate a unique integer for each objects key. I don''t know if Lua will allow me to push/to an integer for the object, but I can always cheat this by casting the integer in and out of a void pointer.
2) This one seems better, but I''m not sure if it''s really safe.
int tolua_ObjectType_new(lua_State* Machine)
{
list<objectType>::iterator* self = new list<objectType>::iterator;
Objects.push_back(ObjectType);
*self = Objects.back();
tolua_topushuserdata(Machine,(void*) self);
}
int tolua_ObjectType_delete(lua_State* Machine)
{
list<objectType>::iterator* self = (list<objectType>::iterator*) tolua_tousertype(Machine,1,0);
Objects.erase(*self);
delete self;
}
I haven''t tested if that last one will actually compile. What do you guys think?