glib/docs/reference/gobject/gvalue.md
2023-10-11 14:01:29 +01:00

3.2 KiB

Title: Generic value container

Generic value container

The [struct@GObject.Value] structure is basically a variable container that consists of a type identifier and a specific value of that type. The type identifier within a GValue structure always determines the type of the associated value.

To create an undefined GValue structure, simply create a zero-filled GValue structure. To initialize the GValue, use the [method@GObject.Value.init] function. A GValue cannot be used until it is initialized.

Once you have finished using a GValue, you must call [method@GObject.Value.unset] to ensure that all the resources associated with the GValue are freed.

The basic type operations (such as freeing and copying) are determined by the [struct@GObject.TypeValueTable] associated with the type ID stored in the GValue. Other GValue operations (such as converting values between types) are provided by this interface.

The code in the example program below demonstrates GValue's features:

#include <glib-object.h>

static void
int2string (const GValue *src_value,
            GValue       *dest_value)
{
  if (g_value_get_int (src_value) == 42)
    g_value_set_static_string (dest_value, "An important number");
  else
    g_value_set_static_string (dest_value, "What's that?");
}

int
main (int   argc,
      char *argv[])
{
  // GValues must be initialized
  GValue a = G_VALUE_INIT;
  GValue b = G_VALUE_INIT;
  const char *message;

  // The GValue starts empty
  g_assert (!G_VALUE_HOLDS_STRING (&a));

  // Put a string in it
  g_value_init (&a, G_TYPE_STRING);
  g_assert (G_VALUE_HOLDS_STRING (&a));
  g_value_set_static_string (&a, "Hello, world!");
  g_printf ("%s\n", g_value_get_string (&a));

  // Reset it to its pristine state
  g_value_unset (&a);

  // It can then be reused for another type
  g_value_init (&a, G_TYPE_INT);
  g_value_set_int (&a, 42);

  // Attempt to transform it into a GValue of type STRING
  g_value_init (&b, G_TYPE_STRING);

  // An INT is transformable to a STRING
  g_assert (g_value_type_transformable (G_TYPE_INT, G_TYPE_STRING));

  g_value_transform (&a, &b);
  g_printf ("%s\n", g_value_get_string (&b));

  // Attempt to transform it again using a custom transform function
  g_value_register_transform_func (G_TYPE_INT, G_TYPE_STRING, int2string);
  g_value_transform (&a, &b);
  g_printf ("%s\n", g_value_get_string (&b));

  g_value_unset (&b);
  g_value_unset (&a);

  return 0;
}

For letting a GValue own (and memory manage) arbitrary types or pointers, they need to become a boxed type. The example below shows how the pointer mystruct of type MyStruct is used as a boxed type.

typedef struct { ... } MyStruct;
G_DEFINE_BOXED_TYPE (MyStruct, my_struct, my_struct_copy, my_struct_free)

// These two lines normally go in a public header. By GObject convention,
// the naming scheme is NAMESPACE_TYPE_NAME:
#define MY_TYPE_STRUCT (my_struct_get_type ())
GType my_struct_get_type (void);

void
foo (void)
{
  GValue *value = g_new0 (GValue, 1);
  g_value_init (value, MY_TYPE_STRUCT);
  g_value_set_boxed (value, mystruct);
  // [... your code ....]
  g_value_unset (value);
  g_free (value);
}