Lua用户数据对象管理
2014-2-18 20:33:13
收藏:0
阅读:189
评论:2
我正在尝试将一个 Lua 类对象推入栈中。多个函数可以返回该对象的指针。
换句话说:我需要推入 userdata 值,同时仍然能在它们上使用“==”,“~=”等。因此,如果它是相同的 C++ 对象,则 userdata 指针必须相同。
-- 这应该将对象推入栈
local firstObject = GetClassObject();
firstObject:doSomething();
firstObject将由Lua脚本存储,稍后在代码中,我将需要再次执行此操作:
-- c++ 类指针在这里没有更改
-- 因此,我希望推送与第一次调用中相同的 userdata 指针...
local object = GetClassObject();
-- 如果不这样做,则以下情况将失败... :C
if object == firstObject then
...
我的 Push 函数应该基本上检查是否已经存在相同的 C++ 类指针,如果是,则推送相应的 userdata 指针(无论我如何推送,对象都应该完全一样)
如果不存在,则应创建一个新的 userdata(将其推送到堆栈上)并将其内容设置为类对象。
这是我的代码:
template <typename T>
void Push( const T &tObject )
{
lua_State *L = GetLuaState();
// 这里我需要检查是否已经有这样一个 C++ 对象(同样的 tObject)!
//
// 如果是,我想要推送相关的 userdata。
// 对象尚不存在 -> 我们需要一个新的 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;
}
LuaToUData 是我编写的一个函数,用于不抛出 Lua 错误:
void* LuaToUData( int nIndex, const char *pszTable )
{
void *pUserData = lua_touserdata( g_luaState, nIndex );
if( pUserData != nullptr )
{
if( lua_getmetatable( g_luaState, nIndex ) != 0 )
{
lua_getfield( g_luaState, LUA_REGISTRYINDEX, pszTable );
bool bEqual = ( lua_rawequal( g_luaState, -1, -2 ) == 1 );
lua_pop( g_luaState, 2 );
if( bEqual )
return pUserData;
}
}
return nullptr;
}
点赞
用户1478081
这是弱表的工作方式吗?
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))
{
//创建新的弱表
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); //不存在,需要弹出
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);
}
2012-06-25 21:06:13
评论区的留言会收到邮件通知哦~
推荐文章
- 如何将两个不同的lua文件合成一个 东西有点长 大佬请耐心看完 我是小白研究几天了都没搞定
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?
- addEventListener 返回 nil Lua
- Lua中获取用户配置主目录的跨平台方法
在Lua中,任何两个相同的userdata实例都保证是相等的。但是,当你像你现在这样封装一个C++类实例时,每个被封装的实例都会被放入一个新的userdatum中,这意味着它们不能直接进行比较。
所以你需要为你的对象定义一个
__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; }这里假设
MyClass有某种operator==重载。你可以将这个函数设置为与你的MyClassuserdata项相关联的元表中的__eq元方法。你似乎已经涵盖了元表处理,所以我在这里不再多说。下一个问题是:你正在封装整个类实例作为lua full userdata项。你可能不希望一次又一次地推送相同的东西,并使用了所有可用内存......如果你只推送指针,则这就不那么成问题,但你并没有这样做。因此,你将需要一些唯一的方式来标识你的C++类的每个实例。这里举个有字符串的例子:
class MyClass { private: std::string _id; public: MyClass(const std::string& id) : _id(id) {} const std::string& get_id() { return _id; } // setters and operator= overrides not included. }; void l_push_thing(lua_State* L, const MyClass& thing) { // try to get our instance by ID from the registry table: lua_getfield(L, LUA_REGISTRYINDEX, thing.id()); // if so, return, leaving it at the top of the stack. if (lua_isuserdata(L, -1)) return; void *ud = lua_newuserdata(L, sizeof(MyClass)); *reinterpret_cast<MyClass*>(ud) = thing; // set up the metatable, etc // duplicate the userdata reference: lua_pushvalue(L, -1); // push our new userdata into the registry. pops the duplicate from the stack lua_setfield(L, LUA_REGISTRYINDEX, thing.get_id()); }(注意:我没有编译或测试过这个例子。可能有误!)
这将在堆栈顶部留下与某个特定
MyClass实例相关联的userdatum。你需要采取自己的步骤来“取消注册”类实例;在这种情况下,每个实例的硬引用存在于注册表中,因此userdatum在你销毁该引用之前将_不会被垃圾回收_。你可能考虑在这里使用弱/短暂表。