Есть ли шанс сохранить безопасность типов и абстракцию памяти с помощью Vala и C ++?

Моя проблема в том, как связать C ++ с Vala, для меня это действительно базовая и фундаментальная проблема, особенно когда речь идет о памяти, изменении структур данных и безопасности типов.

Обычные ответы о таких вещах, как:

  • Вы можете «легко перевести это на C»
  • Вы можете использовать некоторую эквивалентную функцию Glib / структуру данных

Проблема в том, что C даже не близко к тому, что может предложить C ++, и это просто другой язык 90% времени; с другой стороны, проблема с Glib заключается в том, что он не является стандартным и не является C ++, и у меня есть много кода на C ++, который я хотел бы использовать повторно безопасным способом, плюс кодирование на C ++ для меня более эффективно.

Так что же происходит, когда я хочу передать std::vector<T> Вала или stringstream ? Что происходит, когда моя программа Vala хочет копировать, ссылаться, редактировать и изменять размеры / перемещать этот контейнер?

Я не знаю, как Vala справляется с этим, потому что vapi и нижняя строка Vala о C, и я не могу найти какой-либо конкретный ответ о том, как обращаться с кодом C ++.

Учитывая, что я уже отказался от GTKmm как реальный вариант, как вы предлагаете мне пойти с Vala & C ++?

1

Решение

Vala не поддерживает C ++. Причина, по которой вы не можете найти ответ о том, как обращаться с кодом C ++, заключается в том, что его нет — вы не можете.

Единственный способ заставить библиотеку C ++ работать с Vala — это сначала написать оболочку на C. Эта оболочка может использовать GLib, если вы хотите — Vala в любом случае требует GLib, поэтому, если вы планируете, чтобы программное обеспечение Vala было единственным потребителем C API, использование GLib на самом деле не добавляет зависимости. Или вы можете написать C-привязки для std :: vector или stringstream.

Если вам нужны примеры оболочек C для библиотек C ++, взгляните на Snappy или LevelDB. Они оба являются довольно хорошими примерами того, как легко создать простую оболочку C, хотя IMHO ни один из них не особенно хорош с точки зрения API (на самом деле, я не думаю, что API C ++ особенно хороши, но я так думаю о большинстве API C ++ …).

Вы не получите безопасность типов для шаблонов C ++ в C API, если хотите сохранить возможность обрабатывать все типы. Вам придется использовать void * (или что-то похожее, например, gpointer) в C API, но вы можете вернуть безопасность типов в Vala с правильными привязками. Например, если бы я хотел создать привязку для std :: vector, часть C API могла бы выглядеть так

/* foo-vector.h */
#ifdef __cplusplus
extern "C" {
#endif

typedef void (*FooDestroyNotify) (void* data);
typedef struct _FooVector FooVector;

FooVector* foo_vector_new (FooDestroyNotify destroy_notify);
void foo_vector_free (FooVector* vec);
void foo_vector_push_back (FooVector* vec, void* value);
void* foo_vector_pop_back (FooVector* vec);

#ifdef __cplusplus
}
#endif

А также

/* foo-vector.cpp */

#include <iostream>
#include <vector>

#include <stdlib.h>

struct _FooVector {
std::vector<void*>* vec;
FooDestroyNotify destroy_notify;
};

FooVector* foo_vector_new (FooDestroyNotify destroy_notify) {
FooVector* vec = (FooVector*) malloc (sizeof (FooVector));

vec->vec = new std::vector<void*>;
vec->destroy_notify = destroy_notify;

return vec;
}

void foo_vector_push_back (FooVector* vec, void* value) {
vec->vec->push_back (value);
}

void* foo_vector_pop_back (FooVector* vec) {
void* res = NULL;
if (!vec->vec->empty ()) {
res = vec->vec->back ();
vec->vec->pop_back ();
}
return res;
}

void foo_vector_free (FooVector* vec) {
if (vec->destroy_notify != NULL) {
std::vector<void*>::iterator it = vec->vec->begin ();

for (; it < vec->vec->end () ; it++) {
vec->destroy_notify (*it);
}
}

delete vec->vec;
free (vec);
}

(Если вы не хотите использовать glib, вы можете просто создать аналогичную typedef вместо использования GDestroyNotify.)

Затем в VAPI

[Compact]
public class Vector<T> {
[CCode (simple_generics = true)]
public Vector ();
public void push_back (owned T value);
public owned T pop_back ();
}

Проблема в том, что он работает только с типами, которые могут быть вставлены в указатель. Со стороны C это в основном то, как все делается, но если вам нужно связать что-то вроде std :: vector, вам нужно либо создать специализированную привязку для этого одного типа, либо смоделировать свой API немного как GArray, где у вас есть обойти размеры (которые будут не быть веселым в использовании от Вала).

3

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


По вопросам рекламы [email protected]