Take the 2-minute tour ×

I'm lead dev for Bitfighter, a game primarily written in C++, but using Lua to script robot players. We're using Lunar (a variant of Luna) to glue the bits together.

I'm now wrestling with how our Lua scripts can know that an object they have a reference to has been deleted by the C++ code.

Here is some sample robot code (in Lua):

if needTarget then                           -- needTarget => global(?) boolean
    ship = findClosest(findItems(ShipType))  -- ship => global lightUserData obj

if ship ~= nil then

Notice that ship is only set when needTarget is true, otherwise the value from a previous iteration is used. It is quite possible (likely, even, if the bot has been doing it's job :-) that the ship will have been killed (and its object deleted by C++) since the variable was last set. If so, C++ will have a fit when we call ship:getLoc(), and will usually crash.

So the question is how to most elegantly handle the situation and limit the damage if (when) a programmer makes a mistake.

I have some ideas. First, we could create some sort of Lua function that the C++ code can call when a ship or other item dies:

function itemDied(deaditem)
    if deaditem == ship then
        ship = nil
        needTarget = true

Second, we could implement some sort of reference counting smart pointer to "magically" fix the problem. But I would have no idea where to start with this.

Third, we can have some sort of deadness detector (not sure how that would work) that bots could call like so:

if !isAlive(ship) then
    needTarget = true
    ship = nil             -- superfluous, but here for clarity in this example


<...as before...>

Fourth, I could retain only the ID of the ship, rather than a reference, and use that to acquire the ship object each cycle, like this:

local ship = getShip(shipID)                 -- shipID => global ID

if ship == nil then
    needTarget = true

    shipID = ship:getID()

<...as before...>

My ideal situation would also throw errors intelligently. If I ran the getLoc() method on a dead ship, I'd like to trigger error handling code to either give the bot a chance to recover, or at least allow the system to kill the robot and log the problem, hopefully cuing me to be more careful in how I code my bot.

Those are my ideas. I'm leaning towards #1, but it feels clunky (and might involve lots of back and forth because we've got lots of short-lifecycle objects like bullets to contend with, most of which we won't be tracking). It might be easy to forget to implement the itemDied() function. #2 is appealing, because I like magic, but have no idea how it would work. #3 & #4 are very easy to understand, and I could limit my deadness detection only to the few objects that are interesting over the span of several game cycles (most likely a single ship).

This has to be a common problem. What do you think of these ideas, and are there any better ones out there?


Here's my current best solution:

In C++, my ship object is called Ship, whose lifecycle is controlled by C++. For each Ship, I create a proxy object, called a LuaShip, which contains a pointer to the Ship, and Ship contains a pointer to the LuaShip. In the Ship's destructor, I set the LuaShip's Ship pointer to NULL, which I use as an indicator that the ship has been destroyed.

My Lua code only has a reference to the LuaShip, and so (theoretically, at least, as this part is still not working properly) Lua will control the lifecycle of the LuaShip once the corresponding Ship object is gone. So Lua will always have a valid handle, even after the Ship object is gone, and I can write proxy methods for the Ship methods that check for Ship being NULL.

So now my task is to better understand how Luna/Lunar manages the lifecycle of pointers, and make sure that my LuaShips do not get deleted when their partner Ships get deleted if there is still some Lua code pointing at them. That should be very doable.

Actually, it turned out not to be doable (at least not by me). What did seem to work was to decouple the Ship and the LuaShip objects a little. Now, when the Lua script requests a LuaShip object, I create a new one and hand it off to Lua, and let Lua delete it when it's done with it. The LuaShip uses a smart pointer to refer to the Ship, so when the Ship dies, that pointer gets set to NULL, which the LuaShip object can detect.

It is up to the Lua coder to check that the Ship is still valid before using it. If they do not, I can trap the sitation and throw out an stern error message, rather than having the whole game crash (as was happening before).

Now Lua has total control over the lifecyle of the LuaShip, C++ can delete Ships without causing problems, and everything seems to work smoothly. The only drawback is that I'm potentially creating a lot of LuaShip objects, but it's really not that bad.

If you are interested in this topic, please see the mailing list thread I posted about a related concept, that ends in some suggestions for refining the above:


share|improve this question
have you tried something more elaborate, such as luabridge or luabind? Both allow for objects with mixed lifetimes (lua/c++) without memory leaks –  Dmitry Ledentsov Aug 14 '13 at 19:18

4 Answers 4

up vote 5 down vote accepted

I don't think you have a probelm on your Lua side, and you should not be solving it there.

Your C++ code is deleting objects that are still being referenced. No matter how they're referenced, that's bad.

The simple solution may be to let Lunar clean up all your objects. It already knows which objects must be kept alive because the script is using them, and it seems feasible to let it also do GC for random C++ objects (assuming smart pointers on the C++ side, of course - each smart pointer adds to Lunars reference count)

share|improve this answer
Yes, you are right. I think the problem is in how Luna/Lunar does its binding. I'm still trying to understand the details, but it appears to use weak tables in its referencing, which I believe do not inhibit gc from deleting objects. Hopefully I can tweak it a bit and tell it not to do that, at least for selected objects (such as the LuaShip I described in my solution above). –  Watusimoto Jun 30 '09 at 18:55

Our company went with solution number four, and it worked well for us. I recommend it. However, in the interests of completeness:

Number 1 is solid. Let the ship's destructor invoke some Lunar code (or mark that it should be invoked, at any rate), and then complain if you can't find it. Doing things this way means that you'll have to be incredibly careful, and maybe hack the Lua runtime a bit, if you ever want to run the game engine and the robots in separate threads.

Number 2 isn't as hard as you think: write or borrow a reference-counting pointer on the C++ side, and if your Lua/C++ glue is accustomed to dealing with C++ pointers it'll probably work without further intervention, unless you're generating bindings by inspecting symbol tables at runtime or something. The trouble is, it'll force a pretty profound change in your design; if you're using reference-counted pointers to refer to ships, you have to use them everywhere - the risks inherent in referring to ships with a mixture of bare pointers and smart ones should be obvious. So I wouldn't go that route, not as late in the project as you seem to be.

Number 3 is tricky. You need a way to determine whether a given ship object is alive or dead even after the memory representing it has been freed. All the solutions I can think of for that problem basically devolve into number 4: you can let dead ships leave behind some kind of token that's copied into the Lua object and can be used to detect deadness (you'd keep dead objects in a std::set or something similar), but then why not just refer to ships by their tokens?

In general, you can't detect whether a particular C++ pointer points to an object that's been deleted, so there's no easy magical way to solve your problem. Trapping the error of calling ship:getLoc() on a deleted ship is possible only if you take special action in the destructor. There's no perfect solution to this problem, so good luck.

share|improve this answer
My current solution (posted at the end of my question) does run up against the threading concern you raised. However, at this time, I don't think threading makes much sense, as my scripts run comfortably at close to 60 frames/sec on an old laptop, and threading would add tons of complexity. I am using a type of smart pointer for the Ship<=>LuaShip connection, so hopefully I'll see the benefits there without having to retrofit the entire game, which would be prohibitive. –  Watusimoto Jun 30 '09 at 18:51

I agree with MSalters, I really don't think you should be freeing the memory from the C++ side. Lua userdata supports the ___gc metamethod to give you a chance to clean things up. If the gc is not agressive enough you can tweak it a bit, or run it manually with a small step size, more often. The lua gc is not deterministic, so if you need to have resources released then you will need to have a function that you can call to release those resources (which will also be called by __gc, with appropriate checks).

You might also want to look into using weak tables for your ship references so that you don't have to assign EVERY reference to nil to get it freed. Have one strong reference (say, in a list of all active ships) then all the others are weak references. When a ship is destroyed, set a flag on the ship that marks it as such, then set the reference to nil in the active ships table. Then, when the other ship wants to interact your logic is the same except you check for:

if ship==nil or ship.destroyed then
  ship = findClosest(findItems(ShipType))
share|improve this answer

This is an old question, but the right solution, IMO, is to have lua_newuserdata() create a shared_ptr or weak_ptr via either boost::shared_ptr/boost::weak_ptr or C++11's std::shared_ptr/std::weak_ptr. From there, you create a reference whenever you need it, or fail if the weak_ptr is unable to obtain lock() a shared_ptr. For example (using Boost's shared_ptr in this example since this is an old question where you probably do not have have C++11 support yet, though for new projects where possible I'd recommend C++11's shared_ptr):

using MyObjectPtr = boost::shared_ptr<MyObject>;
using MyObjectWeakPtr = boost::weak_ptr<MyObject>;

auto mySharedPtr = boost::make_shared<MyObject>();
auto userdata = static_cast<MyObjectWeakPtr*>(lua_newuserdata(L, sizeof(MyObjectWeakPtr)));
new(userdata) MyObjectWeakPtr(mySharedPtr);

And then when you need to get a C++ object:

auto weakObj = *static_cast<MyObjectWeakPtr*>(
    luaL_checkudata(L, 1, "MyObject.Metatable"));
luaL_argcheck(L, weakObj != nullptr, 1, "'MyObjectWeakPtr' expected");

// If you're using a weak_ptr, this is required!!!! If your userdata is a
// shared_ptr, you can just act on the shared_ptr after luaL_argcheck()
if (auto obj = weakObj.lock()) {
  // You have a valid shared_ptr, the C++ object is alive and you can
  // dereference like a normal shared_ptr.
} else {
  // The C++ object went away, you can safely garbage collect userdata

It's critical that you don't forget to deallocate the weak_ptr in your lua __gc metamethod:

static int
myobject_lua__gc(lua_State* L) {
  auto weakObj = *static_cast<MyObjectWeakPtr*>(
      luaL_checkudata(L, 1, "MyObject.Metatable"));

Don't forget to make use of macros or template metaprogramming to avoid much of the code duplication re: static_cast<>, luaL_argcheck(), etc.

Use shared_ptr when you need to keep the C++ object alive for as long as the lua object also exists. Use weak_ptr when C++ may reap the object and it's okay for it to disappear out from under lua's feet. ALWAYS use either shared_ptr or weak_ptr when the life of an object is not known and needs to be managed automatically by refcount.

Tip: have your C++ class inherit from boost::enable_shared_from_this or std::enable_shared_from_this because it enables use of shared_from_this().

share|improve this answer

Your Answer


