【问题标题】:How to handle C++ class construct failure in Lua如何在 Lua 中处理 C++ 类构造函数失败
【发布时间】:2019-01-03 12:01:28
【问题描述】:

我使用 SWIG 绑定 C++ 类,以便在 Lua 中使用它们。

不知道是否可以在Lua中处理C++类的构造失败。

例如,我有以下Test 类,它在构造时尝试获取用户数据。

void *getUserdata(lua_State *L, const char *key)
{
    lua_pushstring(L, key);
    lua_gettable(L, LUA_REGISTRYINDEX);
    return lua_touserdata(L, -1);
}

class Test
{
public:
    Test(lua_State *L)
    :data(static_cast<MyData *>(getUserdata(L, "my_name"))){};

    void setDataNum(int num)
    {
        data->num = num;
    }
private:
       MyData *data;
};

但是,如果 getUserdata() 返回 nullptr,则调用 setDataNum() 会使我的应用程序崩溃。

我想知道是否有任何方法可以检测和处理构造失败(在这种情况下data 变为nullptr),因此类不会在 Lua 中创建。

【问题讨论】:

  • 您能否创建一个 lua 类,让您在调用 getUserdata 创建的类之前检查您首先从 lua 调用的 userData 的状态?
  • 您说您正在使用 SWIG,但您正在直接操作 Lua 堆栈,并且您发布的示例不是 SWIG 接口文件。对我来说,不清楚你在问什么。
  • @HenriMenke 对不起,我的 SWIG 接口文件中有这段代码:%typemap(default) (lua_State *L) { $1 = L; } 这就是它可以直接操作 Lua 堆栈的方式。也许我应该为Test 类创建一个类型映射来处理异常?
  • 既然可以将它们保存为Test 的私有成员,为什么还要将它们保存为用户数据? "my_name" 的用户数据中有什么?你有点违背了 SWIG 的目的,即在 C++ 和脚本语言之间给你一个清晰的界限。
  • @cuinjune 我明白了。我也没有像现在那样支持你的问题,这应该会让你超过 15 个代表。

标签: c++ class constructor lua swig


【解决方案1】:

错误处理的第一步是检查错误。来自Lua reference manual

void *lua_touserdata (lua_State *L, int index);

如果给定索引处的值是完整的用户数据,则返回其块地址。如果该值是轻量级用户数据,则返回其指针。否则,返回NULL

这意味着我们可以通过检查data 是否为NULL 来轻松检查调用是否成功。那我们就可以采取相应的行动了,我选择抛出异常。

test.hpp

#pragma once
#include <stdexcept>

#include <lua.hpp>

struct MyData {
    int num;
};

void *getUserdata(lua_State *L, const char *key) {
    lua_pushstring(L, key);
    lua_gettable(L, LUA_REGISTRYINDEX);
    return lua_touserdata(L, -1);
}

class Test {
public:
    Test(lua_State *L)
        : data(static_cast<MyData *>(getUserdata(L, "my_name"))) {
        if (data == nullptr) {
            throw std::runtime_error("invalid userdata at \"my_name\"");
        }
    };

    void setDataNum(int num) { data->num = num; }

private:
    MyData *data;
};

Lua 无法消化此异常,默认情况下,解释器只会以terminate called after throwing an instance of 'std::runtime_error' 崩溃。这不是很好,我们宁愿将异常转换为 Lua 错误。 SWIG 附带support for that

test.i

%module example
%{
#include "test.hpp"
%}

%include <exception.i>
%exception {
    try {
        $action
    } catch (std::exception const &e) {
        SWIG_exception(SWIG_RuntimeError, e.what());
    }
}

%typemap(default) (lua_State *L) { $1 = L; }
%include "test.hpp"

Lua 没有异常,因此没有 try-catch 块。相反,Lua 有 pcall 的受保护调用的概念。这将返回一个标志调用是否成功以及调用的结果或错误。

local example = require("example")
local success, c = pcall(example.Test)
if (success) then
    c:setDataNum(1)
else
    print(c)
end

调用示例:

$ swig -c++ -lua test.i
$ clang++ -Wall -Wextra -Wpedantic -I /usr/include/lua5.2 -fPIC -shared test_wrap.cxx -o example.so -llua5.2
$ lua5.2 test.lua
SWIG_RuntimeError:invalid userdata at "my_name"

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-07-05
    • 2017-10-21
    • 2011-01-21
    • 2023-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多