Странный вывод для функции luajit ffi, возвращающей строку

У меня есть функция, подобная следующей, которая возвращает c-строку из другой функции, возвращающей std::string.

const char* GetFilePath(const char* aFilename)
{
    return FileSystem->GetFilePath(aFilename).c_str();
}

Если я вызову эту функцию из lua, я получу только мусор. Если я изменю функцию, чтобы она возвращала, например, «Тест», она работает.

Я думаю, это потому, что деструктор возвращаемого std::string будет вызван и, следовательно, удалит строку, сделав c-строку недействительной.

Мой вопрос, как я могу предотвратить это? Как я могу заставить это работать?

ОБНОВЛЕНИЕ: я предоставляю эту функцию Lua со следующим.

local ffi = require('ffi')
ffi.cdef[[
const char* GetFilePath(const char* aFilename)
]]

x = ffi.string(GetFilePath("Script.lua"))
io.write(x)

Этот код просто печатает какой-то случайный мусор. Но если я изменю функцию C-Wrapper, чтобы она просто возвращала строку C-Style, я получаю желаемый результат.

Обновление 2: например, если я сделаю что-то вроде следующего:

const char* GetFilePath(const char* aFilename)
{
    return aFilename;
}

Он работает так, как ожидалось. Также, когда я открываю некоторые другие функции, возвращающие const char*. НО, если я сделаю следующее:

const char* GetFilePath(const char* aFilename)
{
    return std::string(aFilename).c_str();
}

Я получаю случайный мусор. Моя исходная функция C++ возвращает std::string.


person TheMasterMaind    schedule 10.06.2016    source источник
comment
В вашем обновлении2 этот код return std::string(aFilename).c_str(); никогда не бывает правильным. Это всегда будет давать неопределенное поведение, независимо от привязок lua ​​или чего-либо еще.   -  person Chris Beck    schedule 11.06.2016


Ответы (1)


Если вы настаиваете на использовании для этого luajit FFI вместо API C, вам придется написать более сложный C++.

Проблема в том, что любая функция, которая возвращает const char * в C++, не может быть сгенерирована путем вызова c_str() для локального или временного std::string, потому что она станет недействительной до того, как lua ​​получит возможность ее использовать.

Самый простой способ обойти это — использовать локальную переменную static, которая не будет уничтожена сразу после возврата из функции.

const char* GetFilePath(const char* aFilename)
{
    static std::string long_lived;
    long_lived = FileSystem->GetFilePath(aFilename);
    return long_lived.c_str();
}

Здесь есть некоторые дополнительные накладные расходы - строка long_lived будет выделена до тех пор, пока GetFilePath не будет вызвана снова или ваша программа не завершится. Но эти строки небольшие, так что эти накладные расходы не имеют большого значения.

person Chris Beck    schedule 11.06.2016
comment
Спасибо за ответ! Это решает мою проблему. Я могу попытаться изменить свой код или снова использовать стандартный lua c api. - person TheMasterMaind; 11.06.2016