Отключение luabind при попытке вызвать метод объекта с ошибками lua

Я использовал пример из http://www.rasterbar.com/products/luabind/docs.html#deriving-in-lua чтобы определить класс в C ++, который я могу получить из lua:

class base
{
public:
base(const char* s)
{ std::cout << s << "\n"; }

virtual void f(int a)
{ std::cout << "f(" << a << ")\n"; }
};

struct base_wrapper : base, luabind::wrap_base
{
base_wrapper(const char* s)
: base(s)
{}

virtual void f(int a)
{
call<void>("f", a);
}

static void default_f(base* ptr, int a)
{
return ptr->base::f(a);
}
};

...

module(L)
[
class_<base, base_wrapper>("base")
.def(constructor<const char*>())
.def("f", &base::f, &base_wrapper::default_f)
];

Затем я создал производный класс в lua:

class 'base_derived' (base)

function base_derived:__init(str)
base.__init(self,str)
end

function base_derived:f()
this_function_doesnt_exist()
end

Любой вызов ‘f’ должен выдавать ошибку lua, которая прекрасно работает, если я делаю это в lua:

local x = base_derived("Test")
x:f() -- Throws "attempt to call a nil value..." error

Я хотел бы сделать эквивалент этого, но в C ++:

auto g = luabind::globals(l);
auto r = g["base_derived"];
if(r)
{
luabind::object o = r("Test");
auto gm = luabind::object_cast<base_wrapper*>(o);
if(gm != nullptr)
{
try
{
luabind::call_member<void>(o,"f",5);
}
catch(luabind::error &e)
{
std::cout<<"[LUA] Error: "<<e.what()<<std::endl;
}
}
o.push(l);
}

Однако вызов ‘luabind :: call_member’ вызывает прерывание в ‘luabind / detail / call_member.hpp’, строка 258:

// Code snippet of luabind/detail/call_member.hpp
~proxy_member_void_caller()
{
if (m_called) return;

m_called = true;

// don't count the function and self-reference
// since those will be popped by pcall
int top = lua_gettop(L) - 2;

// pcall will pop the function and self reference
// and all the parameters

push_args_from_tuple<1>::apply(L, m_args);
if (pcall(L, boost::tuples::length<Tuple>::value + 1, 0))
{
assert(lua_gettop(L) == top + 1);
#ifndef LUABIND_NO_EXCEPTIONS
////////////////////////////////////////////
throw luabind::error(L); // LINE 258
////////////////////////////////////////////
#else
error_callback_fun e = get_error_callback();
if (e) e(L);

assert(0 && "the lua function threw an error and exceptions are disabled.""If you want to handle this error use luabind::set_error_callback()");
std::terminate();
#endif
}
// pops the return values from the function
stack_pop pop(L, lua_gettop(L) - top);
}

Исключение в этой строке на самом деле не выдается, но именно оно вызывает прерывание.

Однако прерывание происходит только в том случае, если lua-функции вызывают ошибку lua. Если я прокомментирую вызов this_function_doesnt_exist (), обе версии lua и c ++ будут работать нормально.

Почему ‘throw luabind :: error (L);’ вызывая прерывание и что я могу сделать, чтобы безопасно вызвать функцию из c ++ даже с потенциальными ошибками lua?

// Редактировать:
Это стек вызовов во время прерывания (когда вызывается luabind :: call_member (o, «f», 5); ‘):

>   vcruntime140d.dll!__CxxFrameHandler(EHExceptionRecord * pExcept, unsigned __int64 RN, _CONTEXT * pContext, _xDISPATCHER_CONTEXT * pDC) Line 213 C++
ntdll.dll!RtlpExecuteHandlerForException()  Unknown
ntdll.dll!RtlDispatchException()    Unknown
ntdll.dll!KiUserExceptionDispatch() Unknown
KernelBase.dll!RaiseException() Unknown
vcruntime140d.dll!_CxxThrowException(void * pExceptionObject, const _s__ThrowInfo * pThrowInfo) Line 136    C++
server.dll!luabind::detail::proxy_member_void_caller<boost::tuples::tuple<int const * __ptr64,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type> >::~proxy_member_void_caller<boost::tuples::tuple<int const * __ptr64,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type> >() Line 258    C++

И это сообщение об отмене:
введите описание изображения здесь

1

Решение

Смотрите строку 254:

if (pcall(L, boost::tuples::length<Tuple>::value + 1, 0))

Вот, pcall просит Луа казнить x:f(5) эквивалентный вызов. Очевидно, этот код возвращает ошибку, потому что pcall () возвращает что-то отличное от нуля. Это ожидается, потому что вы в самом деле создавая ошибку в lua, вызывая this_function_doesnt_exist(), Это также объясняет, почему прерывание не происходит, когда вы комментируете this_function_doesnt_exist() вызов.

Затем к коду C ++:

     throw luabind::error(L);

Эта ошибка выдается из деструктора: ~proxy_member_void_caller()и оказывается, что выбрасывать исключение из деструктора — плохая практика. Эта проблема известна для luabind (увидеть этот вопрос) для вызова прерывания, даже не бросая.

Решение состоит в том, чтобы добавить noexcept(false)на подпись ~proxy_member_void_caller(), как это:

~proxy_member_void_caller() noexcept(false)
2

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector