2

I'm wondering if it's possible to access all of the userdata "tables" (is it called userdata tables?) and then delete them from Lua because this is my problem:

a = Object(5, 5)
a:Delete()
a:SetPosition(3,3)

As you can see first I create an object and save an pointer to a c++ class called Object which is allocated using "new" in my map class. Then I delete the object which means I delete the allocated memory for the pointer in my map class. And last I call SetPosition, if the memory still is allocated for the c++ Object class everything will run fun. But if it is deletes (as it is in this case because we called Delete() before the SetPosition(...) call) my program will crash. So what I'm wondering is following:

Is it possible to set the varaible 'a' in lua to nil by calling Delete ? I know I could do something like 'a = a:Delete()' if Delete return nil but if I forget to do the 'a =' part it fail. Also I'm wondering if it's possible to delete the userdata and check if it doesn't exist when I call SetPositon(), if it doesn't I will just return.

Also, the base code is from: http://lua-users.org/wiki/SimpleCppBinding

Yu Hao
  • 119,891
  • 44
  • 235
  • 294
user1188404
  • 75
  • 1
  • 7

3 Answers3

4

First, let me answer your question:

Is it possible to set the varaible 'a' in lua to nil by calling Delete ?

No. There is no means to do what you're saying. And there's a reason for that: what you're trying to do is terrible code.

Lua is a garbage collected system. Lua should not be expected to delete objects. If Lua gets a pointer to some external object, then either your code owns it or Lua owns it.

If your code owns it, Lua should not be deleting it. Lua can use it for some period of time. But it is up to your Lua code to use it for exactly and only that period of time. Once its lifetime has expired, Lua shouldn't be talking to it anymore.

This is no different from dealing with pointers to objects in C and C++. If your function is handed a naked pointer (ie: not a smart pointer), your code needs to know how long it can reasonably expect to talk to that object. Can it store it? How long can it store a pointer to that object? When will that object die, and who's responsible for destroying it?

If you pass an object to Lua such that Lua now owns the object, Lua shouldn't be explicitly deleting it either. Lua is a garbage collected system; you should attach a __gc metamethod to your type, so that Lua's garbage collector will call your code when the userdata is collected. That way, you can call destructors, free memory, etc.

When you give Lua something that now belongs to Lua, it should look like a regular Lua object. You don't call Delete methods for tables and strings you create in Lua; you let the garbage collector do its job. It is your job, as the one writing the C++-to-Lua interface, to ensure that the objects you give to Lua behave the way that Lua wants them to.

In cases where you need to do significant resource management, where you want Lua to release resources as quickly as possible (such as for file handles, etc), then you need to store a pointer to your C++ object inside of the non-light userdata. That's the pointer you NULL out. All of your interface functions on that object will check the pointer to see if it's NULL and simply do nothing or raise an error.

Lua's file handles (returned by io.open) are a good example of this. If you try to call functions on them, Lua throws a Lua error.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • Thanks. But this is the case: When I create my object, it should be drawn on the screen instantly and when the script is over I don't want the object do be deleted via the garbage collector. I want the object to be "alive" until I tell it to be deleted via another lua script. It seems like using a garbage collector and delete the objects will just cause the Object to instantly be deleted. What I'm developting is a game where you can script npc events and create and delete npcs at the go without any game crashes. – user1188404 Feb 06 '12 at 23:06
  • 1
    Did you read all of the post? Particularly the "In cases where you need to do significant resource management..." paragraphs? That being said, I can't say that I agree with your API being based on the presence/absence of the object. You could just delete the `lua_State` (which causes all garbage to be collected) when the event is over. Let the garbage build up until then. The user can have a function to hide an entity (so that it doesn't get drawn), but they can unhide it later if they so desire. – Nicol Bolas Feb 06 '12 at 23:13
  • Yeah I thought about hiding NPCs and also move the pointers of these npcs to some kind of std::vector called hidden/removed npcs and delete them when the current map is over? Just wondering what would happend after an hour of playing at the same map "/ Maby you've spawned 50.000 NPCs in total. Also the scripts for my game will just be used as trigger scripts which means when I walk on a trigger area a script will run and something will happend(a npc could spawn) The script may just run for some second, maby less. Then I could clean up the "hidden" npcs when no scrips are running? – user1188404 Feb 06 '12 at 23:24
3

In the Delete method, set the metatable of the received object to nil and you'll get an error message if you later call a method on that object.

lhf
  • 70,581
  • 9
  • 108
  • 149
  • Oh tell me more please! Which function should I use? – user1188404 Feb 06 '12 at 23:30
  • Like this? luaL_getmetatable(L, "nil"); lua_setmetatable(L, -2); – user1188404 Feb 06 '12 at 23:36
  • 3
    If the object is at the top of the stack, which it will when you enter `a:Delete()`, then do ` lua_pushnil(L); lua_setmetatable(L,1);`. See my libraries at http://www.tecgraf.puc-rio.br/~lhf/ftp/lua/ for this technique in action. – lhf Feb 06 '12 at 23:47
  • Ok it's wokring kind of. Get an error after calling delete and call another function like SetPosition(): 'Attempt to index global 'a' (a userdata value). Ok so is it possible in any way to do something like: 'if a then a:SetPosition(5,7) end' in cases like these? – user1188404 Feb 06 '12 at 23:53
  • 2
    I said you'd get an error. The error message is as expected. It's just telling you that `a` no longer understands the methods it used to. And, no, there is no way to set it to nil. – lhf Feb 06 '12 at 23:59
  • Is it possible to get all the objects and set all of the meta tables to nil? – user1188404 Feb 07 '12 at 12:03
  • And I want a function like this: 'a = GetNpc(index)' How would I do that without allocating another npc.. ? – user1188404 Feb 07 '12 at 12:26
1

I'd rather advice using SWIG or LuaBind instead, they've already taken care of such pitfalls for you.

vines
  • 5,160
  • 1
  • 27
  • 49
  • I wouldn't say that they take care of such things. Neither provides a delete method (they use GC properly). What they provide is a way to control ownership. You still have to use these tools correctly and actually manage ownership of objects. – Nicol Bolas Feb 06 '12 at 22:55
  • @NicolBolas Agree. I suppose, adequate ownership control is the simplest solution here, since nullifing the userdata alone would yield little anyway, as you've already pointed out. These tools would just allow to concentrate on it, rather than on inventing, say, wrappers for smart pointers. – vines Feb 06 '12 at 23:11