mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-12-28 16:36:14 +01:00
7b2ac3c82e
Signed-off-by: Philip Withnall <pwithnall@gnome.org> Helps: #3037
129 lines
4.7 KiB
Markdown
129 lines
4.7 KiB
Markdown
Title: Floating References
|
||
|
||
# Floating References
|
||
|
||
**Note**: Floating references are a C convenience API and should not be used
|
||
in modern GObject code. Language bindings in particular find the concept
|
||
highly problematic, as floating references are not identifiable through
|
||
annotations, and neither are deviations from the floating reference
|
||
behavior, like types that inherit from [class@GObject.InitiallyUnowned] and
|
||
still return a full reference from [`id@g_object_new`].
|
||
|
||
[class@GObject.InitiallyUnowned] is derived from [class@GObject.Object]. The
|
||
only difference between the two is that the initial reference of a
|
||
`GInitiallyUnowned` is flagged as a "floating" reference. This means that it
|
||
is not specifically claimed to be "owned" by any code portion. The main
|
||
motivation for providing floating references is C convenience. In
|
||
particular, it allows code to be written as:
|
||
|
||
```c
|
||
container = create_container ();
|
||
container_add_child (container, create_child());
|
||
```
|
||
|
||
If `container_add_child()` calls [`method@GObject.Object.ref_sink`] on the
|
||
passed-in child, no reference of the newly created child is leaked. Without
|
||
floating references, `container_add_child()` can only acquire a reference
|
||
the new child, so to implement this code without reference leaks, it would
|
||
have to be written as:
|
||
|
||
```c
|
||
Child *child;
|
||
container = create_container ();
|
||
child = create_child ();
|
||
container_add_child (container, child);
|
||
g_object_unref (child);
|
||
```
|
||
|
||
The floating reference can be converted into an ordinary reference by
|
||
calling `g_object_ref_sink()`. For already sunken objects (objects that
|
||
don't have a floating reference anymore), `g_object_ref_sink()` is
|
||
equivalent to [`method@GObject.Object.ref`] and returns a new reference.
|
||
|
||
Since floating references are useful almost exclusively for C convenience,
|
||
language bindings that provide automated reference and memory ownership
|
||
maintenance (such as smart pointers or garbage collection) should not expose
|
||
floating references in their API. The best practice for handling types that
|
||
have initially floating references is to immediately sink those references
|
||
after `g_object_new()` returns, by checking if the `GType` inherits from
|
||
`GInitiallyUnowned`. For instance:
|
||
|
||
```c
|
||
GObject *res = g_object_new_with_properties (gtype,
|
||
n_props,
|
||
prop_names,
|
||
prop_values);
|
||
|
||
// or: if (g_type_is_a (gtype, G_TYPE_INITIALLY_UNOWNED))
|
||
if (G_IS_INITIALLY_UNOWNED (res))
|
||
g_object_ref_sink (res);
|
||
|
||
return res;
|
||
```
|
||
|
||
Some object implementations may need to save an object's floating state
|
||
across certain code portions (an example is `GtkMenu` in GTK3), to achieve
|
||
this, the following sequence can be used:
|
||
|
||
```c
|
||
// save floating state
|
||
gboolean was_floating = g_object_is_floating (object);
|
||
g_object_ref_sink (object);
|
||
// protected code portion
|
||
|
||
...
|
||
|
||
// restore floating state
|
||
if (was_floating)
|
||
g_object_force_floating (object);
|
||
else
|
||
g_object_unref (object); // release previously acquired reference
|
||
```
|
||
|
||
## Replacing floating references with annotations
|
||
|
||
You should avoid basing your object hierarchy on floating references, as
|
||
they are hard to understand even in C, and introduce additional limitations
|
||
when consuming a GObject-based API in other languages.
|
||
|
||
One way to express the ownership transfer between ‘container’ and ‘child’
|
||
instances is to use ownership transfer annotations in your documentation and
|
||
introspection data. For instance, you can implement this pattern:
|
||
|
||
```c
|
||
container_add_child (container, create_child ());
|
||
```
|
||
|
||
without leaking by having `container_add_child()` defined as:
|
||
|
||
```c
|
||
/**
|
||
* container_add_child:
|
||
* @self: a container
|
||
* @child: (transfer full): the child to add to the container
|
||
*
|
||
* ...
|
||
*/
|
||
void
|
||
container_add_child (Container *container,
|
||
Child *child)
|
||
{
|
||
container->children = g_list_append (container->children, child);
|
||
}
|
||
```
|
||
|
||
The container does not explicitly acquire a reference on the child; instead,
|
||
the ownership of the child is transferred to the container. The transfer
|
||
annotation will be used by language bindings to ensure that there are no
|
||
leaks; and documentation tools will explicitly note that the callee now owns
|
||
the value passed by the caller.
|
||
|
||
## Replacing floating references with weak references
|
||
|
||
Another option for replacing floating references is to use weak references
|
||
in place of strong ones. A ‘container’ can acquire a weak reference on the
|
||
‘child’ instance by using [`method@GObject.Object.weak_ref`]. Once the
|
||
child instance loses its last strong reference, the container holding a
|
||
weak reference is notified, and it can either remove the child from its
|
||
internal list, or turn a weak reference into a strong one.
|