mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-12-25 15:06:14 +01:00
docs: Move floating refs documentation to Markdown
And add some new sections on strategies for avoiding designing APIs around floating refs. Helps: #3037
This commit is contained in:
parent
58019515d6
commit
e298f1a078
128
docs/reference/gobject/floating-refs.md
Normal file
128
docs/reference/gobject/floating-refs.md
Normal file
@ -0,0 +1,128 @@
|
||||
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.
|
@ -42,6 +42,7 @@ show_class_hierarchy = true
|
||||
urlmap_file = "urlmap.js"
|
||||
# The same order will be used when generating the index
|
||||
content_files = [
|
||||
"floating-refs.md",
|
||||
"boxed.md",
|
||||
"enum-types.md",
|
||||
]
|
||||
|
@ -73,6 +73,7 @@ endif
|
||||
expand_content_files = [
|
||||
'boxed.md',
|
||||
'enum-types.md',
|
||||
'floating-refs.md',
|
||||
]
|
||||
|
||||
gobject_gir = meson.current_source_dir() / 'GObject-2.0.gir'
|
||||
|
@ -54,86 +54,6 @@
|
||||
* GObjects and their methods, see the [GType conventions][gtype-conventions].
|
||||
* For the high-level concepts behind GObject, read [Instantiatable classed types:
|
||||
* Objects][gtype-instantiatable-classed].
|
||||
*
|
||||
* ## Floating references # {#floating-ref}
|
||||
*
|
||||
* **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 #GInitiallyUnowned and still return
|
||||
* a full reference from g_object_new().
|
||||
*
|
||||
* GInitiallyUnowned is derived from GObject. 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:
|
||||
*
|
||||
* |[<!-- language="C" -->
|
||||
* container = create_container ();
|
||||
* container_add_child (container, create_child());
|
||||
* ]|
|
||||
*
|
||||
* If container_add_child() calls g_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 g_object_ref() the new child,
|
||||
* so to implement this code without reference leaks, it would have to be
|
||||
* written as:
|
||||
*
|
||||
* |[<!-- language="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 g_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:
|
||||
*
|
||||
* |[<!-- language="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 objects floating state
|
||||
* across certain code portions (an example is #GtkMenu), to achieve this,
|
||||
* the following sequence can be used:
|
||||
*
|
||||
* |[<!-- language="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
|
||||
* ]|
|
||||
*/
|
||||
|
||||
/* --- macros --- */
|
||||
|
Loading…
Reference in New Issue
Block a user