如何在 package.preload 函数中破坏 C++ class
How to destruct C++ class inside package.preload function
我在使用 SWIG 包装的 Lua 中使用 C++ classes。
由于我使用的是单个 Lua_State
,因此我希望能够在不调用 lua_close(L)
.[=29= 的情况下释放 Lua 脚本的特定块中的变量]
我决定使用 package.preload['name']
以便在需要时可以使用 require 'name'
从其他块访问一个块。
有人告诉我,package.preload
函数中的变量在我执行以下操作后被释放:
package.preload['name'] = nil
package.loaded['name'] = nil
但是,似乎我的自定义 C++ classes 即使在这之后也没有被破坏。
这是我的完整示例代码:
在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
(SWIG界面生成MyBindings.cpp
)
%module my
%{
#include "MyBindings.h"
%}
%include <stl.i>
%include <typemaps.i>
%include "MyBindings.h"
结果:
Class Constructed
为什么 class 析构函数没有被调用以及如何正确地析构 package.preload
函数中的 classes 和变量?
您始终可以通过 obj.~class() 显式调用 d'tor。
如果您在 Lua 包装器中使用外部 classes,我不认为他们可以遵循 C++ 中存在的正确嵌套 d'tor 范例。
我无法重现您的问题,但您的代码中还有其他缺点,最明显的是缺少 header 守卫。文件 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 是一种垃圾收集语言,即当垃圾收集器认为有必要时,析构函数将 运行。您可以在 Lua 中使用 lua_gc
in C or using collectgarbage
手动 运行 垃圾收集器,但 我强烈建议不要 运行 手动设置垃圾收集器 通常会对性能产生负面影响(即使您 运行 它手动希望提高性能)。只有当您 运行 在内存 非常 有限的环境中并且您刚刚 p运行ed 一个 table 或类似的东西。
无论如何,我已经在Lua中为您准备了使用上面编译的my.so
模块的示例。
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 :-)
我在使用 SWIG 包装的 Lua 中使用 C++ classes。
由于我使用的是单个 Lua_State
,因此我希望能够在不调用 lua_close(L)
.[=29= 的情况下释放 Lua 脚本的特定块中的变量]
我决定使用 package.preload['name']
以便在需要时可以使用 require 'name'
从其他块访问一个块。
有人告诉我,package.preload
函数中的变量在我执行以下操作后被释放:
package.preload['name'] = nil
package.loaded['name'] = nil
但是,似乎我的自定义 C++ classes 即使在这之后也没有被破坏。
这是我的完整示例代码:
在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
(SWIG界面生成MyBindings.cpp
)
%module my
%{
#include "MyBindings.h"
%}
%include <stl.i>
%include <typemaps.i>
%include "MyBindings.h"
结果:
Class Constructed
为什么 class 析构函数没有被调用以及如何正确地析构 package.preload
函数中的 classes 和变量?
您始终可以通过 obj.~class() 显式调用 d'tor。 如果您在 Lua 包装器中使用外部 classes,我不认为他们可以遵循 C++ 中存在的正确嵌套 d'tor 范例。
我无法重现您的问题,但您的代码中还有其他缺点,最明显的是缺少 header 守卫。文件 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 是一种垃圾收集语言,即当垃圾收集器认为有必要时,析构函数将 运行。您可以在 Lua 中使用 lua_gc
in C or using collectgarbage
手动 运行 垃圾收集器,但 我强烈建议不要 运行 手动设置垃圾收集器 通常会对性能产生负面影响(即使您 运行 它手动希望提高性能)。只有当您 运行 在内存 非常 有限的环境中并且您刚刚 p运行ed 一个 table 或类似的东西。
无论如何,我已经在Lua中为您准备了使用上面编译的my.so
模块的示例。
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 :-)