Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/lua/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ LuaPlus和c++;垃圾回收事件的回调_C++_Lua - Fatal编程技术网

C++ LuaPlus和c++;垃圾回收事件的回调

C++ LuaPlus和c++;垃圾回收事件的回调,c++,lua,C++,Lua,我一直在与LuaPlus合作,用脚本语言公开模块的功能。为此,LuaPube确实很棒,但我一直坚持对我的裸露对象进行清理,因为我不知道如何处理代表我的C++对象的LUA对象的删除,这样我就可以正确地释放C++资源。p> 我使用lua表和元表来表示cpp对象,将指向cpp对象的指针作为表的lightuserdata参数“\uu object”传递,这样我就可以执行以下操作 function foo() local p = MyCppObject:new() //Create a cpp

我一直在与LuaPlus合作,用脚本语言公开模块的功能。为此,LuaPube确实很棒,但我一直坚持对我的裸露对象进行清理,因为我不知道如何处理代表我的C++对象的LUA对象的删除,这样我就可以正确地释放C++资源。p> 我使用lua表和元表来表示cpp对象,将指向cpp对象的指针作为表的lightuserdata参数“\uu object”传递,这样我就可以执行以下操作

function foo() 
  local p = MyCppObject:new()   //Create a cpp object and bind it to a table+metatable
  p:do_something()        //Correctly calls the cpp member function do_something
  ....
  (exits scope)           //No more references to p, so p is deleted.
 end
在函数退出后(或稍后的某段时间),我希望得到对的调用,在这里我调用内部cpp对象的delete,但我根本看不到调用我的cpp回调。我尝试使用lua的函数强制垃圾收集,多次调用我的函数来强制lua收集我的对象,但我看不到我的回调正在执行。最重要的是,我看到调用collectgarbage(“count”)的结果有时会减少,因此某些内容会被删除,但我不知道是什么。我检查了lua文档,没有发现我做错了什么:(

任何评论都将不胜感激!谢谢


更新:添加C++代码侧+添加本地作为MUD + +我的测试样本/P> 我创建了我的程序的这个小样本。LuaShell对象只是状态的包装器+读取命令行并执行从std::cin读取的字符串的循环

#include <iostream>
#include "LuaPlus.h"
class Point
{
  private:
      int x_,y_;
  public:
  Point(): x_(0), y_(0){}
  Point(int a, int b): x_(a), y_(b){}

  ~Point() {std::cout << "Point "<< x_ << ","
                      << y_ << "being deleted" << std::endl;} 

  int x() const  { return x_;} 
  int y() const  { return y_;}     
};

LuaPlus::LuaObject metatable;

int new_point( LuaPlus::LuaState* state)
{
  LuaPlus::LuaStack args(state);
  //std::cout << "Creating point!!" << std::endl;
  float x = 0, y = 0;
  if ( args.Count() == 3)
  {
      if (args[2].IsNumber() && args[3].IsNumber())
      {
          x = args[2].GetFloat();
          y = args[3].GetFloat();
      }
  }

  Point* p = new Point(x,y);
  LuaPlus::LuaObject lua_obj = state->CreateTable();
  lua_obj.SetLightUserData("__object", p);
  lua_obj.SetMetaTable( metatable );

  return 1;
}

int my_gc_event( LuaPlus::LuaState* state) 
{
  std::cout << "Calling gc_event from lua" << std::endl;
  return 0;
}

int main()
{

  /* Creating the object that holds the Lua interpreter as well as 
   * the command line
   */ 
  LuaShell::Shell shell(true);
  LuaPlus::LuaObject globals = shell.get_state()->GetGlobals();

  metatable = globals.CreateTable("PointMetaTable");
  metatable.SetObject("__index", metatable);
  metatable.Register("new", new_point);
  metatable.Register("__gc",my_gc_event);
  metatable.RegisterObjectDirect("x", (Point*)0 ,&Point::x);
  metatable.RegisterObjectDirect("y", (Point*)0 ,&Point::y);
  globals.SetObject("Point", metatable);

  //Get into the read-command-line-until-quit loop.
  shell.run();
  return 0;
}
如您所见,根据lua运行时,存在“一些”垃圾收集,但当我看到进程的顶部报告时,内存只会上升,而不会下降。此外,我从未看到来自点析构函数的消息(预期我不会真正调用它)或来自“my_gc_事件”内部的消息(出乎意料,因为我认为它在收集垃圾的过程中被调用了)

再次感谢

function foo() 
  p = MyCppObject:new()   //Create a cpp object and bind it to a table+metatable
  p:do_something()        //Correctly calls the cpp member function do_something
  ....
  (exits scope)           //No more references to p, so p is deleted.
end
p
是全局的,因此当
foo
返回时,它不会离开作用域。如果您希望将关键字
local
从词汇上限定为该函数的作用域,则需要使用该关键字

lightuserdata参数[…]我希望得到对元表方法“\uuu gc”的调用

这可能与您的问题无关(我不知道LuaBind是如何工作的),但我认为值得一提


对评论的答复:

我编写了以下测试,它创建了一个单字节、不做任何事情的用户数据类型,该类型的元表中只有一个
\uu gc

#include "lauxlib.h"

static int foo_gc (lua_State* L) { 
   puts("__gc called");
   return 0; 
}

static int foo_new (lua_State* L) { 
   lua_newuserdata(L, 1);
   luaL_getmetatable(L, "foo");
   lua_setmetatable(L, -2);
   return 1;
}

int __declspec(dllexport) __cdecl luaopen_luagc (lua_State* L) {
   // create foo type
   static const struct luaL_reg foo[] = {
      { "__gc",        foo_gc       },
      NULL, NULL
   };
   luaL_newmetatable(L, "foo");
   luaL_openlib(L, NULL, foo, 0);

   // create constructor
   lua_register(L, "foo", foo_new);
   return 0;
}
如果我随后运行以下测试:

require 'luagc'

for i=1,5 do
   foo()
end

collectgarbage("collect")
输出为:

__gc called
__gc called
__gc called
__gc called
__gc called

考虑到评论中隐藏了正确的答案(泥浆道具),我认为最好在这里添加最终代码和答案

正如Mud所说,我的问题是试图使用表来公开对象。虽然这是可行的,但Lua5.1运行时(由luaplus使用)并不调用垃圾收集器事件(uu gc)对于表,所以我不得不使用luaplus的BoxPointer帮助函数。还添加了一个映射来跟踪作为void*传递的暴露对象的类型,之后需要正确地强制转换它们以进行适当的清理。使用一些模板技巧,我以一个非常简单的清理系统结束。下面是代码(主函数和点类定义保持不变)

#包括
#包括
#包括
#包括
#包括“LuaPlus.h”
#包括“Shell.h”
//用于删除创建的对象并向lua公开的函数
模板
void delete_包装(void*ptr)
{
键入要删除的内容*键入的内容=静态内容转换(ptr);
删除键入的\u ptr;
}
//我的对象元表
LuaPlus::LuaObject元表;
//用于保存函数指针以正确删除公开对象的表
std::map g_对象类型删除器;
int new_point(LuaPlus::LuaState*state)
{
LuaPlus::LuaStack args(状态);
浮动x=0,y=0;
如果(args.Count()==3)
{
如果(args[2].IsNumber()&&args[3].IsNumber())
{
x=args[2].GetFloat();
y=args[3]。GetFloat();
}
}
点*p=新点(x,y);
//这以前是一个表,但是考虑到gc的缺点,现在使用这个版本
LuaPlus::LuaObject lua_obj=state->BoxPointer(p);
lua_obj.可设置元表(metatable);
//保存回调以删除我们刚刚创建的对象。
g_object_type_deleter[static_cast(p)]=boost::bind(delete_wrapper,_1);
返回1;
}
int my_gc_事件(LuaPlus::LuaState*状态)
{
//获取lua试图删除的指针。
void*p=state->unexpointer(1);
//查找包含类型信息的delete回调
std::map::iterator it=g_object_type_deleter.find(p);
if(it==g_object_type_deleter.end())
{
std::cout优先);
返回0;
}

谢谢大家!

关于函数中变量的作用域,你们说得对。但即便如此,我还是希望在执行“for 1=1100 do foo()end”之类的操作时收到get回调。我的“xxx:new()”每次都返回一个新表,因此即使变量是全局的,也会分配一个新对象,并在某个时候收集旧对象(我是否应该编辑我的问题以澄清这一点?)关于lightuserdata,它是返回的表中的一个值,而不是返回的直接变量。我看到了与您指出的相同的限制,但我认为作为带有元表的表,我会得到回调,我错了吗?只是指出您帖子中看起来不一样的内容,因为我们看不到您的实际代码。如果这些内容不正确UE,我知道你的问题是什么。我明白,并且非常感谢时间。我将用代码的C++侧更新一点来显示我的问题。用一个工作的例子来更新我的帖子。这个问题缺少重要信息。例如,你说你有一个垃圾收集的元。关于metamethod。好吧,证明一下;告诉我们你是如何用metatable和metamethod创建这个表的。毕竟,你可能做错了。
__gc called
__gc called
__gc called
__gc called
__gc called
#include <iostream>
#include <map>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include "LuaPlus.h"
#include "Shell.h"


//Function used to delete an object created and exposes to lua
template<typename type_to_delete>
void delete_wrapper(void* ptr)
{
    type_to_delete* typed_ptr = static_cast<type_to_delete*>(ptr);
    delete typed_ptr;
}

//My object metatable
LuaPlus::LuaObject metatable;
//Table to save function pointers for the correct deletion of exposed objects
std::map<void*,boost::function<void(void*)> > g_object_type_deleter;

int new_point( LuaPlus::LuaState* state)
{
    LuaPlus::LuaStack args(state);
    float x = 0, y = 0;
    if ( args.Count() == 3)
    {
        if (args[2].IsNumber() && args[3].IsNumber())
        {
            x = args[2].GetFloat();
            y = args[3].GetFloat();        
        }
    }

    Point* p = new Point(x,y);
    //This used to be a table, but given the shortcoming with the gc, now using this version
    LuaPlus::LuaObject lua_obj = state->BoxPointer(p);
    lua_obj.SetMetaTable( metatable );

    //Save the callback to delete the object we just created.
    g_object_type_deleter[static_cast<void*> (p)] = boost::bind( delete_wrapper<Point> , _1);
    return 1;
}

int my_gc_event( LuaPlus::LuaState* state) 
{
    //get the pointer lua is trying to delete.
    void *p = state->UnBoxPointer(1);

    //look for the delete callback with the type information
    std::map<void*,boost::function<void(void*)> >::iterator it = g_object_type_deleter.find(p);
    if (it == g_object_type_deleter.end() )
    {
        std::cout << "receiving callback to destroy object that was not indexed !" << std::endl;
        return 0;
    }
    //Actually call the delete function passing the pointer as parameter
    it->second(it->first);
    return 0;
}