从Lua传递给C++的对象地址,在成员变量中返回了错误的值。

我目前正在尝试使用SWIG工具来生成C ++和Lua代码的包装,进行一些实验。

在与SWIG斗争一番后(尝试设置它,学习它的工作原理等等),我终于获得了一个运行良好的示例。

但是,在我的某个实验中出现了尴尬的结果。

我试图将Lua的userdata恢复为C ++并更改其中的一些值。

下面是我在控制台结果中得到的内容:

控制台



C++: index.cpp
Lua: Foo.lua

C++: Constructor of 0xb2d9f0
Lua: Adress of lFoo = userdata: 0xb35048

C++: Set - Old = 12 New = 4
Lua: Foo->Value = 4

Lua: Bye World

C++: Lua's lFoo To C++
C++: Adress of lFoo = 0xb35048
C++: Foo->Value = 1
C++: Set - Old = 1 New = 44
C++: Popping Foo from Lua
C++: Closing lLuaState
C++: Destructor of 0xb2d9f0
C++: Bye World

在我陈述事情对我而言有混淆之处之前,让我粘贴一些此示例中的其他代码,以便控制台输出变得不那么抽象:

Foo.h


#ifndef FOO_H_
#define FOO_H_

#include <iostream>

class Foo
{
    public:
        Foo(int a_value);
        virtual ~Foo();

        int getValue() { return m_value; }
        void setValue(int a_value)
        {
            std::cout << "C++: Set - Old = " << m_value << " New = " << a_value << "\n";
            m_value = a_value;
        }
    private:
        int m_value;
};

#endif /* FOO_H_ */

Foo.cpp


#include "Foo.h"

Foo::Foo(int a_value) : m_value(a_value)
{
    std::cout << "C++: Constructor of " << this << "\n";
    //setValue(a_value);
}

Foo::~Foo()
{
    std::cout << "C++: Destructor of " << this << "\n";
}

index.cpp


#include <string>
#include <iostream>
#include <lua.hpp>

#include "Foo.h"

extern "C" int luaopen_Foo(lua_State* L); // declare the wrapped module

const std::string ctLuaFooFile = "Foo.lua";

int main(int argc, char* args[])
{
    std::string lLuaFile = ctLuaFooFile;

    std::cout << "C++: index.cpp\n";

    lua_State* lLuaState;

    lLuaState = lua_open();

    luaL_openlibs(lLuaState);

    luaopen_Foo(lLuaState);

    Foo* lFoo;

    if (luaL_loadfile(lLuaState, lLuaFile.c_str()) == 0) // load and run the file
    {
        int lError = lua_pcall(lLuaState, 0, 0, 0);

        if (lError)
        {
            std::cout << "Lua Error: " << lua_tostring(lLuaState, -1);
            lua_pop(lLuaState, 1); /* pop error message from the stack */
        }

        std::cout << "C++: Lua's lFoo To C++\n";

        lua_getglobal(lLuaState, "lFoo");

        lFoo = static_cast<Foo*>(lua_touserdata(lLuaState, -1));

        std::cout << "C++: Adress of lFoo = " << lFoo << "\n";

        std::cout << "C++: Foo->Value = " << lFoo->getValue() << "\n";

        lFoo->setValue(44);

        std::cout << "C++: Popping Foo from Lua\n";
        //Is Foo's destructor invoked here? --No
        lua_pop(lLuaState, -1);
    }
    else
    {
        std::cout << "unable to load" << lLuaFile << "\n";
    }

    std::cout << "C++: Closing lLuaState \n";
    //Foo's destructor getting invoked here!
    lua_close(lLuaState);

    std::cout << "C++: Bye World\n";

    if (lFoo)
    {
        delete lFoo;
    }

    return 0;
}

现在,对于我在控制台输出中得到的那些东西,我将告诉您我的问题在哪里:

1º - 为什么,当我从lFoo中获取引用返回到C ++时,在行lFoo = static_cast<Foo *>(lua_touserdata(lLuaState,-1));中,它的地址是0xb35048(似乎是特定的Lua指针),而不是出现在C ++代码的0xb2d9f0

2º - 即使这些指针在不同的地址上,它们似乎都指向相同的Foo对象(或者至少是“一个”Foo对象),除了当我检查C ++ lFoo->getValue()时,我得到1而不是4。为什么呢?

我考虑过可能得到了第二个Foo对象,但他的构造函数从未被调用。

3º - 另外,当我将我的Foo的引用传回C ++时,我是否做错了什么?有更好的方法吗?

4º - 最后,当我调用lua_close(lLuaState);时,Foo的析构函数被调用。有没有办法让我在C ++端更改销毁此对象的责任?我想我在SWIG文档中读到过有关此问题的内容,但我似乎记不起来在哪里了。


对于那些愿意尝试我的实验的人,我将在此留下Foo.i接口文件,该文件由SWIG工具用于创建Foo_wrap.cxx,以及我使用的Eclipse,SWIG和g ++编译器的控制台命令:

Foo.i


/* File : example.i */
%module Foo

%{
#include "Foo.h"
%}

/* Let's just grab the original header file here */
%include "Foo.h"

控制台命令


**** Build of configuration Debug for project SwigDemo ****

make pre-build main-build
Criando wrappers para lua
swig -c++ -lua ../Foo.i

Building file: ../Foo.cpp
Invoking: GCC C++ Compiler
g++ -I/usr/include/lua5.1 -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"Foo.d" -MT"Foo.d" -o"Foo.o" "../Foo.cpp"
Finished building: ../Foo.cpp

Building file: ../Foo_wrap.cxx
Invoking: GCC C++ Compiler
g++ -I/usr/include/lua5.1 -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"Foo_wrap.d" -MT"Foo_wrap.d" -o"Foo_wrap.o" "../Foo_wrap.cxx"
Finished building: ../Foo_wrap.cxx

Building file: ../index.cpp
Invoking: GCC C++ Compiler
g++ -I/usr/include/lua5.1 -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"index.d" -MT"index.d" -o"index.o" "../index.cpp"
Finished building: ../index.cpp

Building target: SwigDemo
Invoking: GCC C++ Linker
g++ -L/usr/lib -L"/home/bruno/Programas/eclipse/workspace/SwigDemo/Debug" -o"SwigDemo"  ./Foo.o ./Foo_wrap.o ./index.o   -llua5.1
Finished building target: SwigDemo

附注:对于长篇的帖子我感到抱歉。如果有改进的方法,我将非常乐意倾听。

原文链接 https://stackoverflow.com/questions/5523979

点赞
stackoverflow用户513598
stackoverflow用户513598
  1. 因为在 C++ 侧输出的指针值 lFoo 与构造的 Foo 对象均不同,因此我们可以得出结论:lFoo 指向的不是 Foo 对象。

  2. lFoo->getValue() 返回的并不是存储在 Foo 对象中的 4,因为 lFoo 上的数据不是 Foo,而是封装。

  3. 以下是一种方法:在 index.cpp 中读取 Foo 模块的内容(不再链接到它):

#include "foo_wrap.cxx"

用以下内容替换:

lFoo = static_cast<Foo*>(lua_touserdata(lLuaState, -1));
void* ptr;
SWIG_ConvertPtr(
    lLuaState, -1, &ptr, SWIGTYPE_p_Foo, SWIG_POINTER_DISOWN);
lFoo = static_cast<Foo*>(ptr);
  1. 如果不想拥有 Foo 值,可以传递 0 而非 SWIG_POINTER_DISOWN
2011-04-02 22:10:55