У меня есть интерфейс C++, для которого я создаю рубиновые привязки с swig. Я могу построить эти привязки, но у меня проблема с сборщиком мусора. Мой код ruby выглядит так:
parser = HeaderParser.new(source_file, ['/usr/lib'])
parser.parse
functions = parser.getFunctions //Array of Ruby wrapped class named Function
functions.each do |f|
puts f.getName
end
Проблема заключается в том, что если сборщик мусора удаляет объект парсера, все вызовы методов Function-объектов приводят к Segfault. Это потому, что мой объект функции C++ просто использует указатель на память, выделенную объектом Parser.
Я хотел бы найти способ сообщить GC не освобождать объект HeaderParser, пока используется объект Function
Я попытался использовать директиву как
%trackbobjects
и написать функцию маркировки ruby для сборщика мусора, как в документации, но без успеха
%header %{
static void mark_HeaderParser(void* ptr) {
TruckBoris::HeaderParser* hp = (TruckBoris::HeaderParser*) ptr;
/* Loop over each object and tell the garbage collector
that we are holding a reference to them. */
std::vector<TruckBoris::Function> fns;
fns = hp->getFunctions();
int count = fns.size();
for(int i = 0; i < count; ++i) {
TruckBoris::Function fn = fns[i];
VALUE object = SWIG_RubyInstanceFor(&fn);
if (object != Qnil) {
rb_gc_mark(object);
}
}
}
%}
Информация о интерфейсе C++ У меня есть основной класс, который инициализирует Clang CompilerInstance и ASTConsumer:
class HeaderParser
{
public:
HeaderParser();
HeaderParser( std::string sourceFile, std::vector<std::string> headersPaths);
~HeaderParser();
...
bool parse(bool mainFile = false);
...
std::vector<Function> getFunctions() const;
...
private:
...
clang::CompilerInstance m_ci;
HeaderElements *m_headerElements; // an ASTConsumer
};
Когда вызывается метод HeaderParser :: parse, он анализирует исходный файл и заполняет вектор объектов Function.
Эти объекты просто используют указатели FunctionDecl в памяти, выделенные компиляторомInstance в The HeaderParser.
class Function
{
public:
Function();
Function(clang::FunctionDecl * fn);
~Function() {}
std::string getName() const;
private:
clang::FunctionDecl * m_function;
};
Поэтому методы класса функций построены следующим образом:
std::string Function::getName() const
{
if(m_function)
return m_function->getNameInfo().getAsString();
else
return std::string();
}
Мне просто нужно было упростить все, чтобы это работало.
В классе HeaderParser вместо прямого возврата std::vector<Function>
с помощью:
std::vector<Function> getFunctions() const;
Я использовал:
int nbFunctions() const;
Function getFunction(int) const;
и, удалите директивы марки, и пусть swig сделает магию. После этого мне просто нужно добавить в свой файл ruby lib:
class Rtruckboris::HeaderParser
def functions
fns=[]
(0..(functions_num() -1)).each do |i|
fns<<get_nth_function(i)
end
fns
end
...