GObject 参考手册:概念:GLib 动态类型系统:复制函数

The major common point between all GLib types (fundamental and non-fundamental, classed and non-classed, instantiable and non-instantiable) is that they can all be manipulated through a single API to copy/assign them.
所有的 Glib 类型(基本和非基本,类化和非类化,可实例化和不可实例化)的最大共同点是都可以通过单一的 API 来复制或指定它们。

The GValue structure is used as an abstract container for all of these types. Its simplistic API (defined in gobject/gvalue.h) can be used to invoke the value_table functions registered during type registration: for example g_value_copy copies the content of a GValue to another GValue. This is similar to a C++ assignment which invokes the C++ copy operator to modify the default bit-by-bit copy semantics of C++/C structures/classes.
GValue 结构被用作所有类型的抽象的容器,它的极度简化的 API(定义在 gobject/gvalue.h)可以被使用请求 value_table 函数被注册当类型注册中:举个例子,g_value_copy 复制了 GValue 的内容至另一个 GValue。这与 C++ 指派它的复制操作来修改默认的按位复制 C++/C 结构是类似的。

The following code shows how you can copy around a 64 bit integer, as well as a GObject instance pointer (sample code for this is located in the source tarball for this document in sample/gtype/test.c):
下面的代码向你展示了你是如何复制一个64位的整型,同样 GObject 的实例指针也是这样(代码在/gtype/test.c中):

static void test_int (void)
{
  GValue a_value = {0, }; 
  GValue b_value = {0, };
  guint64 a, b;
 
  a = 0xdeadbeaf;
 
  g_value_init (&a_value, G_TYPE_UINT64);
  g_value_set_uint64 (&a_value, a);
 
  g_value_init (&b_value, G_TYPE_UINT64);
  g_value_copy (&a_value, &b_value);
 
  b = g_value_get_uint64 (&b_value);
 
  if (a == b) {
    g_print ("Yay !! 10 lines of code to copy around a uint64.\n");
  } else {
    g_print ("Are you sure this is not a Z80 ?\n");
  }
}
 
static void test_object (void)
{
  GObject *obj;
  GValue obj_vala = {0, };
  GValue obj_valb = {0, };
  obj = g_object_new (MAMAN_TYPE_BAR, NULL);
 
  g_value_init (&obj_vala, MAMAN_TYPE_BAR);
  g_value_set_object (&obj_vala, obj);
 
  g_value_init (&obj_valb, G_TYPE_OBJECT);
 
  /* g_value_copy's semantics for G_TYPE_OBJECT types is to copy the reference.
     This function thus calls g_object_ref.
     It is interesting to note that the assignment works here because
     MAMAN_TYPE_BAR is a G_TYPE_OBJECT.
   */
  g_value_copy (&obj_vala, &obj_valb);
 
  g_object_unref (G_OBJECT (obj));
  g_object_unref (G_OBJECT (obj));
}

The important point about the above code is that the exact semantics of the copy calls is undefined since they depend on the implementation of the copy function. Certain copy functions might decide to allocate a new chunk of memory and then to copy the data from the source to the destination. Others might want to simply increment the reference count of the instance and copy the reference to the new GValue.
上面代码的重点是关于复制指令的确切语义,并没有详细的定义复制是如何实现的。复制函数的实现可能是决定请求一新块的内存,并把数据从源复制到目的。或者可能是简单的增加实例的引用数和复制引用至新的 GValue。

The value_table used to specify these assignment functions is defined in gtype.h and is thoroughly described in the API documentation provided with GObject (for once 😉 which is why we will not detail its exact semantics.
value_table 用于详细说明这些定义在 gtype.h 的函数的使用并彻底地描述在由 GObject 提供的API文档中,这是为什么我们不追究细节的原因。

typedef struct _GTypeValueTable         GTypeValueTable;
struct _GTypeValueTable
{
  void     (*value_init)         (GValue       *value);
  void     (*value_free)         (GValue       *value);
  void     (*value_copy)         (const GValue *src_value,
                                  GValue       *dest_value);
  /* varargs functionality (optional) */
  gpointer (*value_peek_pointer) (const GValue *value);
  gchar            *collect_format;
  gchar*   (*collect_value)      (GValue       *value,
                                  guint         n_collect_values,
                                  GTypeCValue  *collect_values,
                                  guint                collect_flags);
  gchar            *lcopy_format;
  gchar*   (*lcopy_value)        (const GValue *value,
                                  guint         n_collect_values,
                                  GTypeCValue  *collect_values,
                                  guint                collect_flags);
};

Interestingly, it is also very unlikely you will ever need to specify a value_table during type registration because these value_tables are inherited from the parent types for non-fundamental types which means that unless you want to write a fundamental type (not a great idea!), you will not need to provide a new value_table since you will inherit the value_table structure from your parent type.
有趣的是,你同样不需要详细指定一个 value_table 在注册过程中,因为 value_tables 一般从非基本类型的父类中继承,这意味着除非你想写一个基本类型,否则你将不需要提供一个新的 value_table 因为它可以从父类继承 value_table。

Please note that there exists another registration function: the g_type_register_dynamic. We will not discuss this function here since its use is very similar to the _static version.
请注意,另外一个注册函数是 g_type_register_dynamic。我们将不讨论这个函数,因为它与 _static 版本非常相似。

Leave a Reply

Your email address will not be published. Required fields are marked *