我有可能用Vala和C ++保持类型安全和内存抽象吗?

时间:2014-07-22 19:35:46

标签: c++ vala

我的问题是如何将C ++与Vala接口,这对我来说是一个非常基本和基本的问题,特别是在内存,修改数据结构和类型安全方面。

通常的答案是:

  • 您可以“轻松将其翻译为C”
  • 您可以使用一些等效的Glib函数/数据结构

问题是C它甚至不接近C ++所能提供的,而且90%的时间它只是不同的语言;另一方面,Glib的问题在于它不是标准的,它也不是C ++,我在C ++中有很多代码,我想以安全的方式重用,加上C ++编码对我来说更有效。< / p>

那么当我想将std::vector<T>传递给Vala或stringstream时会发生什么?当我的Vala程序想要复制,引用,编辑和调整/重新定位该容器时会发生什么?

我不知道Vala如何处理这个因为vapi和Vala的底线是关于C的,我找不到任何关于如何处理C ++代码的具体答案。

考虑到我已经放弃了GTKmm作为一个真正的选择,你怎么建议我应该使用Vala&amp; amp; C ++?

1 个答案:

答案 0 :(得分:3)

Vala不支持C ++。你无法找到关于如何处理C ++代码的答案的原因是没有 - 你不会。

从Vala获取C ++库的唯一方法是首先在C中编写一个包装器。如果你愿意,那个包装器可以使用GLib - Vala需要GLib,所以如果你计划使用GLib作为C API的唯一消费者,Vala并不真正添加依赖。或者你可以为std :: vector或stringstream编写C绑定。

如果您想要C ++库的C包装器示例,请查看Snappy或LevelDB。它们都是很好的例子,说明创建一个简单的C包装器是多么容易,虽然从API的角度来看,恕我直言并不是特别好(实际上,我不认为C ++ API特别好,但我觉得这样关于大多数C ++ API ...)。

如果您希望保留处理所有类型的能力,那么您不会在C API中获得C ++模板的类型安全性。您将不得不在C API中使用void *(或类似的东西,如gpointer),但您可以使用正确的绑定在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,其中你必须传递大小(这些从Vala使用起来很有趣。)