[Date Prev][Date Next][Thread Prev][Thread Next]
- Subject: Re: Userdata Lifetime Management
- From: Vinnie Falco <vinnie.falco@...>
- Date: Wed, 4 Jul 2012 15:32:29 -0700
> From: Carsten Fuchs <firstname.lastname@example.org>
> a) Can we store custom attributes in the Lua objects?
> For example, in the Lua code in section
> <https://github.com/vinniefalco/LuaBridge#lua-lifetime>, will these statements be valid?
> a.temporaryLuaOnlyNum = 1.0;
> a.temporaryLuaOnlyStr = "hello";
> a.LuaEventCallback = function(x, y) ... end
Unfortunately, that's not going to work, since LuaBridge's userdata
metatables provide both __index and __newindex.
> b) Will it prevent the garbage collection of "a" (my original problem)?
Yes, it will. LuaBridge userdata comes in three "flavors":
1) A full class object. The object is actually layed out inside the
userdata. This is accomplished with placement new. As you can imagine,
this is "Lua lifetime". When Lua collects it, the object disappears
(its destructor is called first). C++ can still receive pointers and
references to this object in callbacks. It will just have to be
careful about remembering such pointers.
2) A pointer to a class object. This is "C++ lifetime." When Lua
collects this userdata, no destructor is called. The C++ code must
make sure that it doesn't delete the object while there are pointers
to it lingering in Lua.
3) A "shared container". This is any copy constructible C++ class
which has a corresponding "ContainerInfo" traits class defined. The
traits tell LuaBridge how to extract a pointer to the underlying class
from the container. These containers are constructed in-place inside
the userdata, using placement new. This is used for the "Shared
> What will happen if Lua wants to garbage collect the now (for Lua) unreachable former
> value of "a"?
This is not supported, since LuaEventCallback cannot be assigned to
the userdata object in any meaningful way.
> c) If I implement a CFunction, how would I type-check a given stack position for a
> C++ class, and how obtain the related object?
Use Userdata::get <T*> (lua_State*, int parameterIndex) where T is
your class type. The return value will be a pointer to your class.
> d) You write that std::shared_ptr<> etc. are not supported because of type erasure.
> (If I understood your description correctly, this is the very problem that intrusive
> smart pointers *don't* have?)
> But, why do you place plain raw pointers in userdata?
Not all userdata contain raw pointers, as mentioned above.
> Wouldn't the problem be solved if the userdata kept a *smart* pointer instance instead?
LuaBridge stores the smart pointer object inside the userdata, for the
Shared lifetime model. However, this does not solve the problem. The
reason that std::shared_ptr<> doesn't work is because of aliasing. Two
different instances of shared_ptr can point to the same object, and
their reference counts will not be shared. This is explained in the
documentation. When Lua passes a shared_ptr wrapped object using
LuaBridge to a C++ function that takes only a pointer to the object,
it has no way of knowing that the object is really wrapped by a smart
LuaBridge comes with two alternative smart pointer objects:
RefCountedPtr, and RefCountedObjectPtr. One uses a global hash table,
and the other is intrusive. These are both explained in the
documentation. These two objects work around the problems with
shared_ptr by providing a way to retrieve the reference count from
only a pointer to the object (and not the smart pointer): one uses a
global table, the other stores the reference count on the object
> Your help would much be appreciated!
Glad to answer any question you have!
Follow me on Github: https://github.com/vinniefalco