[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: linking tables to C++ objects?
- From: Graham Wakefield <lists@...>
- Date: Mon, 26 Feb 2007 16:31:32 -0800
On Feb 26, 2007, at 1:50 PM, Rici Lake wrote:
On 26-Feb-07, at 4:08 PM, Graham Wakefield wrote:
It depends on why you need to export the table to Lua. (Note:
I call this table the "peer table" below.) Often,
you can just export the userdata directly, and make the table
the userdata's environment; then the userdata's __index meta
points to the environment, and the environment's __index meta
points to your base instance-method table for the object type.
Unfortunately, that requires creating an individual metatable
for each userdata, in addition to the peer table; combining
the two is possible but somewhat less protective.
Yes, I've been trying this approach today; mapping __index and
__newindex metamethods of the userdata to the userdata environment
table. A disadvantage of this is that in Lua my object behaves as a
table for general use, but not as a table for functions such as
table.foreach() and generic for, which could be confusing for end
users. Is there a way to implement a next() method for the generic
for construction?
Sorry I didn't understand why there needs to be an individual
metatable per instance? I'm interested in efficiency since I will
have so many of these instances.
As to the why: I want users to be able to create a kind of table with
user-defined values & functions; and then have callbacks occur at
later times (via a C++ scheduler) on these tables, as part of a
general multimedia performance tool.
Since a userdata's environment table is not garbage collected
until after the userdata's __gc metamethod is run, the __gc
metamethod can still access the peer table.
This is useful to know! Thanks.
In any event, if the translation from c++ pointer to userdata
is done in the context of a known lua_CFunction (or a small
set of them), you can keep the translation table (lightuserdata
to userdata) as an upvalue of the lua_CFunction(s), thus saving
a REGISTRY lookup. That makes translations almost twice as fast,
but you need to create all the closures of the lua_CFunctions
with the upvalue, which is not always convenient.
In fact in my case, there are probably less than 5 lua_CFunctions, so
this is a very viable solution for the table->userdata lookup.
But the question is how I can get from a C++ pointer (after the main
Lua chunk has run) to the Lua userdata. This is not a call from Lua
to C++ triggered by a lua_CFunction, it is a call from C++ to Lua
triggered by a C++ callback. How do I push the userdata onto the
stack, from a C++ instance pointer? For this, I could not find any
other solution than the REGISTRY:
REG[ptr] = udata
If the C++ object can be destroyed when the last Lua
reference to it is gone, and if it has no destructor
(and none of its members have destructors), then you
could allocate it directly into a userdata with
placement new, and thereby avoid the __gc metamethod
altogether. That's only occasionally feasible, but it's
worth keeping in mind. Also, remember that with Lua 5.1,
you can provide a custom allocator to Lua, if that helps
you at all.
I just googled 'placement new', since I was not familiar with it;
indeed this could be a great solution in my case. I still need the gc
() method because the pointer still will be referenced in C++, but I
can clear that reference in the gc() method.
So it would be something like:
// allocate:
MyClass * c = new(lua_newuserdata(L, sizeof(MyClass))) MyClass();
// and then on __gc():
c->~MyClass(); // this call must remove all other C++ references to
the object c
If I do this, I presume that there is still no way to push the
userdata on the stack using the MyClass * c pointer? It's a shame
there is no lua_pushuserdata() function, but I do understand why
there wouldn't be. I still need to add REG[ptr] = udata; where now
ptr == c.
Surely there is a more efficient way to do this!?
Hope some of the above helped.
Yes indeed, thank you very much! This list is always so helpful!