diff options
author | Lauro Neto <lauro.neto@openbossa.org> | 2009-11-30 19:13:52 -0300 |
---|---|---|
committer | Lauro Neto <lauro.neto@openbossa.org> | 2009-12-03 17:15:48 -0300 |
commit | 88d1620754d316d14bfb7f47db1ea39bf12b0cee (patch) | |
tree | aafb334c07850ea46527d18adeebd46ec79c0cb6 /doc | |
parent | fb8e301e45907c43b65a2b7a17dd7f6363746e3a (diff) |
Initial ownership documentation
Reviewed by Marcelo Lira <marcelo.lira@openbossa.org>
Diffstat (limited to 'doc')
-rw-r--r-- | doc/_templates/index.html | 16 | ||||
-rw-r--r-- | doc/commandlineoptions.rst | 22 | ||||
-rw-r--r-- | doc/contents.rst | 2 | ||||
-rw-r--r-- | doc/ownership.rst | 143 |
4 files changed, 168 insertions, 15 deletions
diff --git a/doc/_templates/index.html b/doc/_templates/index.html index a92815e25..8ee5ef20d 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 ddd864a48..eede06b31 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 f6735ee83..85751f6fc 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 000000000..64fa77a5b --- /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() + + |