如何在LuaJIT FFI/C++绑定中使用shared_ptr?

我正在创建一个将Lua绑定到另一个C++项目的项目。经过一些调查,LuaJIT FFI似乎是实现该目标的最佳选择。我真的从lua用户邮件列表归档[1]和另一个相关幻灯片[2]中受益。实际上,这里已经完成了一个Hello World示例[3],并且欢迎提出改进建议。

目前,我正在尝试将shared_ptr引入到此示例中,以便我不需要担心垃圾收集问题。但由于我在Lua和LuaJIT上的经验不足,Lua脚本总是返回Segmentation fault,我甚至不知道如何调试。下面列出了代码段,并希望您这些有才华的人能给我一些实用的建议。

这是“hello.cpp”,我使用的命令来创建库是g++ -std=c++11 -shared -fPIC -o libhello.so hello.cpp

#include<memory>
using namespace std;

class Hello {
    public:
        const char* World()
        {
             return "Hello World!\n";
         }
};

typedef shared_ptr<Hello> pHello;

extern "C" {
    pHello Hello_new(){
        return pHello();
    }

    const char* Hello_World(pHello self){
        return self->World();
    }
}

这是“hello.lua”,运行命令是luajit hello.lua

ffi = require('ffi')
ffi.cdef[[
    typedef struct pHello pHello;

    pHello Hello_new();
    const char* Hello_World(pHello);
]]
hello = ffi.load('hello')

hello_index = {
    World = hello.Hello_World
}
hello_mt = ffi.metatype('pHello', {
    __index = hello_index
})
Hello = hello.Hello_new

hello = Hello()
io.write(ffi.string(hello:World()))
点赞
用户199201
用户199201

Things don't work like you expect them to do.

首先,你的 C++ 代码有缺陷:调用 return pHello() 会返回一个空的 shared_ptr,没有被管理的对象(即:空指针)。如果你想创建一个新的对象,请调用 return std::make_shared< Hello >()

除此之外,使用 shared_ptr 对垃圾回收并没有帮助。智能指针执行的引用计数依赖于析构函数的调用,这是一种 C++ 机制。由于 FFI 库与 C 代码进行交互,无论你如何包装它以传递给 LuaJIT,这都不会发生(你的编译器应该已经警告了你使用 extern "C" 与类类型的返回类型一起的情况)。

标准的做法(如果你想依赖垃圾回收)是让 __gc 元方法调用一个在 C++ 方面执行 delete 的函数。这是 C 的方法:你在函数调用中分配了一个资源,那么你就需要在之后负责释放它。

我建议在你的类周围编写一个简单的包装器,可能首先使用纯 Lua API 来学习基础知识。当你拥有共享对象并不想亲自对其进行引用计数时,可以稍后再将其包装为 shared_ptr

2016-04-20 15:14:48