gpt4 book ai didi

c - 使用 tolua++ 绑定(bind)结构和 ctor/dtor

转载 作者:太空宇宙 更新时间:2023-11-03 23:56:35 25 4
gpt4 key购买 nike

假设我想将一段代码绑定(bind)到 Lua,如下所示:

typedef struct bar {
void * some_data;
} bar;
bar * bar_create(void);
void bar_do_something(bar * baz);
void bar_free(bar * baz);

我想从 Lua 脚本创建这些对象,而不是显式管理它们的生命周期。最好,我希望我的脚本能写

require "foo"
local baz = foo:bar()
baz:do_something()
baz = nil

问题:为了按预期工作,我需要以某种方式告诉 tolua++ bar_create 和 bar_free 是 bar 的构造函数/析构函数。我怎么做?对于类,tolua++ 声称自动使用它们的 ctor/dtor,但对于结构?

我能想到的最好的事情就是 foo.pkg 的定义:

module foo {
struct bar {
static tolua_outside bar_create @ create();
tolua_outside bar_do_something @ do_something();
tolua_outside bar_free @ free();
};
}

这意味着我必须显式调用 create() 和 free()。

最佳答案

可以使用 tolua++ 将 bar 函数导入到 Lua 中并包装以产生对象样式的接口(interface),包括垃圾收集。

为了演示参数的传递,我将 bar 接口(interface)更改为

bar * bar_create(int x);
int bar_do_something(bar * baz, int y);
void bar_free(bar * baz);

并编写了一个测试实现,在调用函数时打印出 xy 等。

bar_create() Lua 函数返回一个用户数据值。 Lua 通过调用存储在数据元表中的 __gc 方法来释放此类用户数据。给定一个 userdata 值和一个析构函数 gc__gc 方法被覆盖,这样它首先调用 gc 然后调用原始的 gc 方法:

function wrap_garbage_collector(userdata, gc)
local mt = getmetatable(userdata)
local old_gc = mt.__gc
function mt.__gc (data)
gc(data)
old_gc(data)
end
end

相同类型的用户数据共享相同的元表;因此,wrap_garbage_collector() 函数应该只为每个类调用一次(假设 tolua++ 的元表只构造一次并仅在退出时释放)。

在这个答案的底部是一个完整的 bar.pkg 文件,它导入了 bar 函数并添加了一个 bar 类到一个 Lua名为 foo 的模块。 foo 模块被加载到解释器 (see for example my SO tolua++ example) 中并像这样使用:

bars = {}

for i = 1, 3 do
bars[i] = foo.bar(i)
end

for i = 1, 3 do
local result = bars[i]:do_something(i * i)
print("result:", result)
end

测试实现打印出发生了什么:

bar(1)
bar(2)
bar(3)
bar(1)::do_something(1)
result: 1
bar(2)::do_something(4)
result: 8
bar(3)::do_something(9)
result: 27
~bar(3)
~bar(2)
~bar(1)

下面 bar 类的构造有点复杂:build_class() 实用程序返回一个类(一个 Lua 表)给定构造函数、析构函数和类方法。毫无疑问需要进行调整,但作为原型(prototype)演示,该示例应该没问题。

$#include "bar.hpp"

// The bar class functions.
bar * bar_create(int x);
int bar_do_something(bar * baz, int y);
void bar_free(bar * baz);

$[
-- Wrapping of the garbage collector of a user data value.
function wrap_garbage_collector(userdata, gc)
local mt = getmetatable(userdata)
local old_gc = mt.__gc
function mt.__gc (data)
gc(data)
old_gc(data)
end
end

-- Construction of a class.
--
-- Arguments:
--
-- cons : constructor of the user data
-- gc : destructor of the user data
-- methods : a table of pairs { method = method_fun }
--
-- Every 'method_fun' of 'methods' is passed the user data
-- as the first argument.
--
function build_class(cons, gc, methods)
local is_wrapped = false
function class (args)
-- Call the constructor.
local value = cons(args)

-- Adjust the garbage collector of the class (once only).
if not is_wrapped then
wrap_garbage_collector(value, gc)
is_wrapped = true
end

-- Return a table with the methods added.
local t = {}
for name, method in pairs(methods) do
t[name] =
function (self, ...)
-- Pass data and arguments to the method.
return (method(value, ...))
end
end

return t
end
return class
end

-- The Lua module that contains our classes.
foo = foo or {}

-- Build and assign the classes.
foo.bar =
build_class(bar_create, bar_free,
{ do_something = bar_do_something })

-- Clear global functions that shouldn't be visible.
bar_create = nil
bar_free = nil
bar_do_something = nil
$]

关于c - 使用 tolua++ 绑定(bind)结构和 ctor/dtor,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4999773/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com