glib/docs/reference/gobject/floating-refs.md

129 lines
4.7 KiB
Markdown
Raw Normal View History

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.