- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在尝试将一个 Lua 类对象压入堆栈。指向该对象的指针可以由多个函数返回。
换句话说:我需要推送 userdata 值,同时仍然保留对它们使用“==”、“~=”等的能力,因此如果 userdata 指针是相同的 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
...
我的 Push 函数应该基本上检查某处是否已经存在相同的 C++ 类指针,如果是,则推送关联的用户数据指针(无论我如何推送,对象应该以 1:1 相同的方式工作)
如果不是,它应该创建一个新的用户数据(将其压入堆栈)并将其内容设置为类对象。
这是我的代码:
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;
}
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;
}
最佳答案
是的,在 Lua 中,相同用户数据 的任何两个实例都保证是相等的。但是,当您像现在这样装箱一个 C++ 类实例时,每个装箱的实例都会放入一个新的用户数据中,这意味着它们不能直接比较。
您需要做的是为您的对象定义一个__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==
覆盖。您可以在与 MyClass
用户数据项关联的元表中将此函数设置为 __eq 元方法。您似乎已经涵盖了元表处理,所以我不会在这里费心。
现在,下一个问题:您将整个类实例打包为 lua 完整用户数据项。您可能不想一遍又一遍地插入相同的事情并用完所有可用的内存......如果您只是插入指针,这不是一个问题,但您没有这样做。所以...您将需要一些独特的方法来识别 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());
}
(注意:我没有编译或测试这个例子。E&OE!)
这会将与某些特定 MyClass
实例关联的用户数据留在堆栈的顶部。您需要采取自己的步骤来“注销”类实例;在这种情况下,注册表中存在对每个实例的硬引用,因此在您销毁该引用之前,用户数据不会被垃圾回收。您可能会考虑在此处使用弱/临时表。
关于c++ - Lua 用户数据对象管理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11177746/
This question already has answers here: Using Variable for Thread group Ramp up time (3个答案) 3年前关闭。 从
我希望使用 RPyC 为硬件板提供 API 作为服务。该板一次只能满足一个用户的需求。有什么方法可以让 RPyC 强制执行一次只有一个用户可以访问吗? 最佳答案 我不确定这是否有效(或有效),但您可以
如果我想以每秒 10 个请求运行测试。如何让 Jmeter 选择每秒处理该请求数所需的最佳线程数。 我将线程数设置为与每秒请求数相同。 最佳答案 您可以使用恒定吞吐量计时器 click here你只需
我正在尝试进行查询以检查客户表并返回过去 30 天、过去 365 天和所有时间具有特定值的用户数。 所有时间的计数很简单: $stmt = $conn->prepare("SELECT count(i
我是一名优秀的程序员,十分优秀!