C++ 用户数据对象管理
我试图将Lua类对象推送到堆栈上。指向该对象的指针可以由多个函数返回C++ 用户数据对象管理,c++,class,lua,lua-userdata,C++,Class,Lua,Lua Userdata,我试图将Lua类对象推送到堆栈上。指向该对象的指针可以由多个函数返回 换句话说,我需要在UpRADIUS数据值的同时保持使用“=”、“~=”等的能力,因此USER数据指针必须是相同的,如果它是同一个C++对象。 -- this should push the object onto the stack local firstObject = GetClassObject(); firstObject:doSomething(); firstObject将由lua脚本存储,稍后在代码中,我需要再
换句话说,我需要在UpRADIUS数据值的同时保持使用“=”、“~=”等的能力,因此USER数据指针必须是相同的,如果它是同一个C++对象。
-- this should push the object onto the stack
local firstObject = GetClassObject();
firstObject:doSomething();
firstObject将由lua脚本存储,稍后在代码中,我需要再次执行此操作:
-- the c++ class pointer has not changed here
-- so I would like to push the same userdata pointer as in the first call...
local object = GetClassObject();
-- if I would not do this the following here would fail... :C
if object == firstObject then
...
推送函数应该基本上检查是否有相同的C++类指针在某处并推导出关联的用户数据指针,如果是这样(不管我如何推它,对象应该工作1:1)
如果没有,它应该创建一个新的userdata(将其推到堆栈上),并将其内容设置为class对象 这是我的密码:template <typename T>
void Push( const T &tObject )
{
lua_State *L = GetLuaState();
// Here i need to check if such a C++ object (the same tObject)
// already exists!
//
// If so i want to push the associated userdata.
// Object didn't exist yet -> we need a new userdata
void *pUserData = lua_newuserdata( L, sizeof( tObject ) );
*reinterpret_cast<T*>( pUserData ) = tObject;
}
template <typename T>
void Push( const T &tObject, const char *pszTable )
{
Push( tObject );
lua_State *L = GetLuaState();
luaL_getmetatable( L, pszTable );
lua_setmetatable( L, -2 );
}
template <typename T>
T& Get( int nIndex )
{
T *pUserData = reinterpret_cast<T*>( lua_touserdata( GetLuaState(), nIndex ) );
if( pUserData == nullptr )
throw std::exception( "Invalid userdata!" );
return *pUserData;
}
template <typename T>
T& Get( int nIndex, const char *pszTable )
{
T *pUserData = reinterpret_cast<T*>( LuaToUData( nIndex, pszTable ) );
if( pUserData == nullptr )
throw std::exception( "Invalid userdata!" );
return *pUserData;
}
对,在Lua中,相同userdata的任意两个实例都保证相等。然而,当你正在练习一个C++类实例时,每个装箱实例都被放入一个新的用户数据表,这意味着它们不能直接比较。 您需要做的是为您的对象定义一个
\uu eq
元方法。它可能看起来有点像这样:
int l_compare_things(lua_State* l)
{
MyClass* a = reinterpret_cast<MyClass*>(lua_touserdata(L, 1));
MyClass* b = reinterpret_cast<MyClass*>(lua_touserdata(L, 2));
lua_pushboolean(L, (*a) == (*b));
return 1;
}
(注意:我没有编译或测试这个示例。E&OE!)
这将使与某个特定的
MyClass
实例关联的userdatum留在堆栈顶部。您需要采取自己的步骤来“注销”类实例;在这种情况下,注册表中存在对每个实例的硬引用,因此在销毁该引用之前,不会对userdatum进行垃圾收集。您可以考虑使用弱/星历表。< P>右,在Lua中,相同用户数据的任何两个实例都保证相等。然而,当你正在练习一个C++类实例时,每个装箱实例都被放入一个新的用户数据表,这意味着它们不能直接比较。
您需要做的是为您的对象定义一个\uu eq
元方法。它可能看起来有点像这样:
int l_compare_things(lua_State* l)
{
MyClass* a = reinterpret_cast<MyClass*>(lua_touserdata(L, 1));
MyClass* b = reinterpret_cast<MyClass*>(lua_touserdata(L, 2));
lua_pushboolean(L, (*a) == (*b));
return 1;
}
(注意:我没有编译或测试这个示例。E&OE!)
这将使与某个特定的
MyClass
实例关联的userdatum留在堆栈顶部。您需要采取自己的步骤来“注销”类实例;在这种情况下,注册表中存在对每个实例的硬引用,因此在销毁该引用之前,不会对userdatum进行垃圾收集。您可以考虑使用弱/星历表。 < P>这是弱表是如何工作的?
void Push( const T &tObject )
{
std::ostringstream o;
o << tObject;
std::string sIdentifier = o.str();
const char *pszIdentifier = sIdentifier.c_str();
lua_State *L = GetLuaState();
luaL_getmetatable( L, "lua_userdata" );
if( !lua_istable( L, -1 ) )
{
// create new weak table
luaL_newmetatable( L, "lua_userdata" );
lua_pushstring( L, "v" );
lua_setfield( L, -2, "__mode" );
}
lua_getfield( L, -1, pszIdentifier );
if( lua_isuserdata( L, -1 ) == TRUE )
return lua_remove( L, -2 );
lua_pop( L, 1 ); // didnt exist yet - getfield is nil -> need to pop that
void *pUserData = lua_newuserdata( L, sizeof( UINT64 ) );
*reinterpret_cast<UINT64*>( pUserData ) = UINT64( tObject );
lua_pushvalue( L, -1 );
lua_setfield( L, -3, pszIdentifier );
lua_remove( L, -2 );
}
void Push(const T&tObject)
{
std::ostringstream o;
你需要把它打开
void*pUserData=lua_newuserdata(L,sizeof(UINT64));
*重新解释铸造(pUserData)=UINT64(tObject);
lua_值(L,-1);
lua_设置域(L,-3,pszIdentifier);
lua_移除(L,-2);
}
弱表就是这样工作的吗
void Push( const T &tObject )
{
std::ostringstream o;
o << tObject;
std::string sIdentifier = o.str();
const char *pszIdentifier = sIdentifier.c_str();
lua_State *L = GetLuaState();
luaL_getmetatable( L, "lua_userdata" );
if( !lua_istable( L, -1 ) )
{
// create new weak table
luaL_newmetatable( L, "lua_userdata" );
lua_pushstring( L, "v" );
lua_setfield( L, -2, "__mode" );
}
lua_getfield( L, -1, pszIdentifier );
if( lua_isuserdata( L, -1 ) == TRUE )
return lua_remove( L, -2 );
lua_pop( L, 1 ); // didnt exist yet - getfield is nil -> need to pop that
void *pUserData = lua_newuserdata( L, sizeof( UINT64 ) );
*reinterpret_cast<UINT64*>( pUserData ) = UINT64( tObject );
lua_pushvalue( L, -1 );
lua_setfield( L, -3, pszIdentifier );
lua_remove( L, -2 );
}
void Push(const T&tObject)
{
std::ostringstream o;
你需要把它打开
void*pUserData=lua_newuserdata(L,sizeof(UINT64));
*重新解释铸造(pUserData)=UINT64(tObject);
lua_值(L,-1);
lua_设置域(L,-3,pszIdentifier);
lua_移除(L,-2);
}
我发现很难准确了解您在这里想要做什么。在创建了LUAUSEDATA实例之后,是否只是试图缓存一个LUAUSEDATA实例?我试图在使用USER数据值的同时保持它们的“使用=”、“~=”等的能力,因此USER数据指针必须是相同的,如果它是同一C++对象。LUA USEDATA对象通过内部引用进行比较。从同一基础指针创建的两个userdata实例应进行相等的比较。你是说在这种情况下,==
不起作用吗?您是否覆盖了\uu eq
元表条目?在这种情况下,'=='检查失败。不,我没有覆盖uuueq…它是否真的比较userdatas内容本身并检查其是否相等?我发现很难准确地计算出您在这里要做什么。在创建了LUAUSEDATA实例之后,是否只是试图缓存一个LUAUSEDATA实例?我试图在使用USER数据值的同时保持它们的“使用=”、“~=”等的能力,因此USER数据指针必须是相同的,如果它是同一C++对象。LUA USEDATA对象通过内部引用进行比较。从同一基础指针创建的两个userdata实例应进行相等的比较。你是说在这种情况下,==
不起作用吗?您是否覆盖了\uu eq
元表条目?在这种情况下,'=='检查失败。不,我没有重写uu eq…它是否真的比较userdatas内容本身并检查其是否相等?为此,很遗憾,我不知道弱/短命表是如何工作的。它们做了什么?我尝试将所有userdata及其值映射到std::map中,并添加了自己的\uu gc
方法,但没有起作用。我将完整的userdata指针按为light userdata,dsn不起作用:c@user1478081一步一个脚印。在基本推送系统正常工作之前,不要担心弱表!我不确定你想用你的std::map
完成什么;你能使用我上面的代码吗?是的,一切正常,但正如你所说的,它会导致内存泄漏。看看下面我是如何修复的:)@user1478081:这至少是个好消息!您使用的是哪个版本的lua?谢谢,很遗憾,我不知道弱/短命表是如何工作的。它们做了什么?我尝试将所有用户数据及其值映射到一个std::map中,并添加了自己的\u gc
方法,但没有起作用。我将完整的userdata指针按为light userdata,dsn不起作用:c@user1478081一步一个脚印。在基本推送系统正常工作之前,不要担心弱表!我不确定你想用你的std::map
完成什么;你能使用我上面的代码吗?是的,一切都正常,但它会导致内存泄漏