summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/_templates/index.html16
-rw-r--r--doc/commandlineoptions.rst22
-rw-r--r--doc/contents.rst2
-rw-r--r--doc/ownership.rst143
4 files changed, 168 insertions, 15 deletions
diff --git a/doc/_templates/index.html b/doc/_templates/index.html
index a92815e2..8ee5ef20 100644
--- a/doc/_templates/index.html
+++ b/doc/_templates/index.html
@@ -9,22 +9,24 @@
<h2>Documentation</h2>
<table class="contentstable" align="center" style="margin-left: 30px"><tr>
<td width="50%">
- <p class="biglink"><a class="biglink" href="{{ pathto("contents") }}">Contents</a><br/>
+ <p class="biglink"><a class="biglink" href="{{ pathto("contents") }}">Contents</a><br/>
<span class="linkdescr">for a complete overview</span></p>
- <p class="biglink"><a class="biglink" href="{{ pathto("typesystemvariables") }}">Type System Variables</a><br/>
- <span class="linkdescr">describes the type system variables that could be used in user custom code</span></p>
- <p class="biglink"><a class="biglink" href="{{ pathto("codeinjectionsemantics") }}">Code Injection Semantics</a><br/>
- <span class="linkdescr">explains how custom code injection is interpreted by {{ project }}</span></p>
+ <p class="biglink"><a class="biglink" href="{{ pathto("faq") }}">FAQ</a><br/>
+ <span class="linkdescr">answers for frequent asked questions</span></p>
<p class="biglink"><a class="biglink" href="{{ pathto("commandlineoptions") }}">Command line options</a><br/>
<span class="linkdescr">explains the few flags used to change {{ project }} behaviour</span></p>
+ <p class="biglink"><a class="biglink" href="{{ pathto("typesystemvariables") }}">Type System Variables</a><br/>
+ <span class="linkdescr">describes the type system variables that could be used in user custom code</span></p>
</td>
<td width="50%">
+ <p class="biglink"><a class="biglink" href="{{ pathto("codeinjectionsemantics") }}">Code Injection Semantics</a><br/>
+ <span class="linkdescr">explains how custom code injection is interpreted by {{ project }}</span></p>
<p class="biglink"><a class="biglink" href="{{ pathto("sequenceprotocol") }}">Sequence Protocol</a><br/>
<span class="linkdescr">support for python sequence protocol</span></p>
+ <p class="biglink"><a class="biglink" href="{{ pathto("ownership") }}">Object Ownership</a><br/>
+ <span class="linkdescr">object ownership features</span></p>
<p class="biglink"><a class="biglink" href="{{ pathto("compiling") }}">Compiling/Installing</a><br/>
<span class="linkdescr">how to compile and install {{ project }}</span></p>
- <p class="biglink"><a class="biglink" href="{{ pathto("faq") }}">FAQ</a><br/>
- <span class="linkdescr">answers for frequent asked questions</span></p>
</td></tr>
</table>
</div>
diff --git a/doc/commandlineoptions.rst b/doc/commandlineoptions.rst
index ddd864a4..eede06b3 100644
--- a/doc/commandlineoptions.rst
+++ b/doc/commandlineoptions.rst
@@ -1,15 +1,21 @@
Command line options
********************
-At the moment, there is just one flag to change the |project| behaviour, ``--enable-parent-ctor-heuristic``. This flag enable an usefull heuristic which can save a lot of work when writing the typesystem.
+Usage
+-----
-This heuristic will be triggered when generating code for a method and:
+::
-* The function is a constructor.
-* The argument name is "parent".
-* The argument type is a pointer to an object.
+ shiboken [options]
-When triggered, the heuristic will set the argument named "parent" as the parent of the current object.
-Being a child of an object means that when the object's parent dies, the C++ instance also dies, so the Python references will be invalidated.
-The main focus of this tag was to remove a lot of hand written code from typesystem when binding Qt libraries, for Qt, this heuristic is never wrong, but be aware that it might be when binding your own libraries.
+Options
+-------
+
+.. _option-heuristic:
+
+``--enable-parent-ctor-heuristic``
+ This flag enable an useful heuristic which can save a lot of work related to object ownership when
+ writing the typesystem.
+ For more info, check :ref:`ownership-parent-heuristics`.
+
diff --git a/doc/contents.rst b/doc/contents.rst
index f6735ee8..85751f6f 100644
--- a/doc/contents.rst
+++ b/doc/contents.rst
@@ -5,7 +5,9 @@ Table of contents
:maxdepth: 3
faq.rst
+ commandlineoptions.rst
typesystemvariables.rst
codeinjectionsemantics.rst
sequenceprotocol.rst
+ ownership.rst
compiling.rst
diff --git a/doc/ownership.rst b/doc/ownership.rst
new file mode 100644
index 00000000..64fa77a5
--- /dev/null
+++ b/doc/ownership.rst
@@ -0,0 +1,143 @@
+****************
+Object ownership
+****************
+
+One of the main things a binding developer should have in mind is
+how the C++ instances lives will cope with Python's reference count.
+The last thing you want is to crash a program due to a segfault
+when your C++ instance was deleted and the
+wrapper object tries to access the invalid memory there.
+
+In this section we'll show how |project| deals with object ownership
+and parentship, taking advantage of the information provided by the
+APIExtractor.
+
+Ownership basics
+================
+
+As any python binding, |project|-based bindings uses reference counting
+to handle the life of the wrapper object (the Python object that contains the
+C++ object, do not confuse with the *wrapped* C++ object).
+When a reference count reaches zero, the wrapper is deleted by Python garbage
+collector and tries to delete the wrapped instance, but sometimes the wrapped
+C++ object is already deleted, or maybe the C++ object should not be freed after
+the Python wrapper go out of scope and die, because C++ is already taking care of
+the wrapped instance.
+
+In order to handle this, you should tell the
+generator whether the instance's ownership belongs to the binding or
+to the C++ Library. When belonging to the binding, we are sure that the C++ object
+won't be deleted by C++ code and we can call the C++ destructor when the refcount
+reaches 0. Otherwise, instances owned by C++ code can be destroyed arbitrarily,
+without notifying the Python wrapper of its destruction.
+
+Invalidating objects
+====================
+
+To prevent segfaults and double frees, the wrapper objects are invalidated.
+An invalidated can't be passed as argument or have an attributte or method accessed.
+Trying to do this will raise RuntimeError.
+
+The following situations can invalidate an object:
+
+C++ taking ownership
+--------------------
+
+ When an object is passed to a function or method that takes ownership of it, the wrapper
+ is invalidated as we can't be sure of when the object is destroyed, unless it has a
+ :ref:`virtual destructor <ownership-virt-method>` or the transfer is due to the special case
+ of :ref:`parent ownership <ownership-parent>`.
+
+ Besides being passed as argument, the callee object can have its ownership changed, like
+ the `setParent` method in Qt's `QObject`.
+
+Invalidate after use
+--------------------
+
+ Objects marked with *invalidate-after-use* in the type system description always are
+ virtual method arguments provided by a C++ originated call. They should be
+ invalidated right after the Python function returns.
+
+.. _ownership-virt-method:
+
+Objects with virtual methods
+----------------------------
+
+ A little bit of implementation details:
+ virtual methods are supported by creating a C++ class, the **shell**, that inherits
+ from the class with virtual methods, the native one, and override those methods to check if
+ any derived class in Python also override it.
+
+ If the class has a virtual destructor (and C++ classes with virtual methods should have), this
+ C++ instance invalidates the wrapper only when the overriden destructor is called.
+
+ One exception to this rule is when the object is created in C++, like in a
+ factory method. This way the wrapped object is a C++ instance of the native
+ class, not the shell one, and we cannot know when it is destroyed.
+
+.. _ownership-parent:
+
+Parent-child relationship
+=========================
+
+One special type of ownership is the parent-child relationship.
+Being a child of an object means that when the object's parent dies,
+the C++ instance also dies, so the Python references will be invalidated.
+Qt's QObject system, for example, implements this behavior, but this is valid
+for any C++ library with similar behavior.
+
+.. _ownership-parent-heuristics:
+
+Parentship heuristics
+---------------------
+
+ As the parent-child relationship is very common, |project| tries to automatically
+ infer what methods falls into the parent-child scheme, adding the extra
+ directives related to ownership.
+
+ This heuristic will be triggered when generating code for a method and:
+
+ * The function is a constructor.
+ * The argument name is `parent`.
+ * The argument type is a pointer to an object.
+
+ When triggered, the heuristic will set the argument named "parent"
+ as the parent of the object being created by the constructor.
+
+ The main focus of this process was to remove a lot of hand written code from
+ type system when binding Qt libraries. For Qt, this heuristic works in all cases,
+ but be aware that it might not when binding your own libraries.
+
+ To activate this heuristic, use the :ref:`--enable-parent-ctor-heuristic <option-heuristic>`
+ command line switch.
+
+Common pitfalls
+===============
+
+Not saving unowned objects references
+-------------------------------------
+
+ Sometimes when you pass an instance as argument to a method and the receiving
+ instance will need that object to live indifinitely, but will not take ownership
+ of the argument instance. In this case, you should hold a reference to the argument
+ instance.
+
+ For example, let's say that you have a renderer class that will use a source class
+ in a setSource method but will not take ownership of it. The following code is wrong,
+ because when `render` is called the `Source` object created during the call to `setSource`
+ is already destroyed.
+
+ .. code-block:: python
+
+ renderer.setModel(Source())
+ renderer.render()
+
+ To solve this, you should hold a reference to the source object, like in
+
+ .. code-block:: python
+
+ source = Source()
+ renderer.setSource(source)
+ renderer.render()
+
+