如何在package.preload函数中破坏C ++类

时间:2018-07-26 11:43:24

标签: c++ class lua swig destructor

我正在用SWIG包装的Lua中使用C ++类。

由于我使用的是单个Lua_State,所以我希望能够在Lua脚本的特定块中释放变量而无需调用lua_close(L)

我决定使用package.preload['name'],以便在需要时可以使用require 'name'从其他块中访问一个块。

在执行以下操作后,我被告知package.preload函数中的变量被释放:

package.preload['name'] = nil
package.loaded['name'] = nil

但是,即使在此之后,似乎我的自定义C ++类也没有被破坏。

这是我的完整示例代码:

Main.cpp

#include "Main.h"

int main()
{
    lua_State *L = luaL_newstate();
    luaL_openlibs(L);
    luaopen_my(L);
    lua_settop(L, 0);
    luaL_dostring(L, "package.preload['test'] = function ()\n"
                         "local test = {}\n"
                         "local class = my.Class()\n"
                         "return test\n"
                     "end\n");
    luaL_dostring(L, "require 'test'");
    luaL_dostring(L, "package.preload['test'] = nil\n"
                     "package.loaded['test'] = nil\n");
}

Main.h

#include "lua.hpp"

extern "C"
{
    int luaopen_my(lua_State *L);
}
int main();

MyBindings.h

#include "Main.h"

class Class
{
public:
    Class()
    {
        std::cout << "Class Constructed" << std::endl;
    };
    ~Class()
    {
        std::cout << "Class Destructed" << std::endl;
    };
};

MyBindings.i中(用于生成MyBindings.cpp的SWIG界面)

%module my
%{
    #include "MyBindings.h"
%}

%include <stl.i>
%include <typemaps.i>

%include "MyBindings.h"

结果:

Class Constructed

为什么不调用类析构函数以及如何正确解构package.preload函数中的类和变量?

2 个答案:

答案 0 :(得分:2)

我无法重现您的问题,但是您的代码中还有其他缺陷,最明显的是缺少标题保护。 Main.h文件不是必需的,而在MyBindings.h文件中则不需要,因为它没有使用它。我不知道您使用的是哪个编译器,但是void main()不是有效的C ++,该标准规定了int main()

Main.cpp

#include "lua.hpp"

extern "C" int luaopen_my(lua_State *L);

int main() {
    lua_State *L = luaL_newstate();
    luaL_openlibs(L);
    luaopen_my(L);
    lua_settop(L, 0);
    luaL_dostring(L, "package.preload['test'] = function ()\n"
                         "local test = {}\n"
                         "local class = my.Class()\n"
                         "return test\n"
                     "end\n");
    luaL_dostring(L, "require 'test'");
    luaL_dostring(L, "package.preload['test'] = nil\n"
                     "package.loaded['test'] = nil\n");
    lua_close(L);
}

MyBindings.h

#pragma once
#include <iostream>

class Class
{
public:
    Class()
    {
        std::cout << "Class Constructed" << std::endl;
    };
    ~Class()
    {
        std::cout << "Class Destructed" << std::endl;
    };
};

MyBindings.i

%module my
%{
#include "MyBindings.h"
%}

%include "MyBindings.h"

示例调用:

$ swig -c++ -lua MyBindings.i
$ clang++ -Wall -Wextra -Wpedantic -I /usr/include/lua5.2 -fPIC -shared MyBindings_wrap.cxx -o my.so -llua5.2
$ clang++ -Wall -Wextra -Wpedantic -I /usr/include/lua5.2 -L . Main.cpp -l:my.so -llua5.2
$ LD_LIBRARY_PATH=. ./a.out 
Class Constructed
Class Destructed

还应注意,Lua是一种垃圾收集语言,即,当垃圾收集器认为有必要时,析构函数将运行。您可以在C中使用lua_gc或在Lua中使用collectgarbage来手动运行垃圾收集器,但强烈建议您不要手动运行垃圾收集器,因为这通常会对性能产生负面影响(即使您手动运行它以提高性能)。只有在内存非常有限的环境中运行并且刚刚修剪了表之类的东西时,手动使用垃圾收集器才有意义。

无论如何,我使用上面编译的my.so模块在​​Lua中为您准备了一个示例。

local my = require("my")
local x = my.Class()
print("Info: Deleting x")
x = nil
print("Info: Collecting garbage")
collectgarbage()
print("Info: Done :-)")
$ lua5.2 test.lua
Class Constructed
Info: Deleting x
Info: Collecting garbage
Class Destructed
Info: Done :-)

答案 1 :(得分:0)

您始终可以通过obj。〜class()显式调用d'tor。 如果您在Lua包装器中使用外部类,那么我不希望它们可以遵循C ++中存在的正确嵌套d'tor范式。