[Kde-bindings] Smoke call policy question

Richard Dale richard.j.dale at gmail.com
Fri Oct 27 17:20:48 UTC 2006


On Friday 27 October 2006 09:57, Dongxu Ma wrote:
> Hi Richard, Ashley and all,
>
> I got a similar scenario in QT4 tutorial:
> #######################
>
>     MyWidget::MyWidget(QWidget *parent)
>
>         : QWidget(parent)
>
>     {
>         setFixedSize(200, 120);
>
>         QPushButton *quit = new QPushButton("Quit", this);
>         quit->setGeometry(62, 40, 75, 30);
>         quit->setFont(QFont("Times", 18, QFont::Bold));
>
>         connect(quit, SIGNAL(clicked()), qApp, SLOT(quit()));
>     }
>
> #######################
>
> 'quit' is a heap variable but will be implicitly deleted by parent widget.
> If one does so in scripting language, for instance in perl, the refcounting
> mechanism will destroy 'quit' since it is out of scope once returning from
> new.
>
> A possible solution for this case: once called with an explicit parent
> widget, I
> can increase the refcount of 'quit' to 2. Thus even the stash is out of
> scope, the
> underlying cpp instance will not be deleted.
>
> This is the case adding stuff into another, while the reverse mentioned in
> boost
> document is more complex. It is very hard to determine, say 'Bar *Foo(...)
> ', the
> returned object is a part of other or a new heap variable. I got such
> situation
> during porting TagLib to Perl. I have to:
> 1). got a part of other / an object reference: allocate a new heap copy.
> this
>         solution has not only performance disadvantage, but also it cannot
> 'export'
>         such internal struct of an object to edit;
>      another possible solution is making the stash behave much more like a
> QT
>         guard pointer;
> 2). got a heap object: do as usual;
>
> The prerequisite is I know what kind of stuff will be returned exactly.
> It will be nice one can get such information from output of smoke.
> Any idea?
I can explain how QtRuby deals with this. Ruby doesn't have ref counting, the
garbage collection is based on 'mark and sweep'. When you create an instance
which wraps a C++ instance you pass it a function which is called during
the 'mark' phase of the garbage collection. So in your example, the mark
function is called for 'MyWidget' and it marks all its children including the
quit button. That means that even if quit is no longer in scope as a local
variable it still won't be gc'd.

If C++ deletes the quit button while a corresponding Ruby instance for it is
still around, there is a callback from the destructors in the Smoke library
into the bindings runtime. That callback allows tidy up operations such as
removing the mapping between the Ruby instance and the underlying C++ one.
The struct of info about the c++ instance, is changed to indicate that Ruby
shouldn't attempt to delete the c++ instance again on garbage collection.

struct smokeruby_object {
    bool allocated;
    Smoke *smoke;
    int classId;
    void *ptr;
};

The 'allocated' boolean indicates whether the instance was created via a Ruby
new method, or in the C++ side. If it is true, then the C++ instance will be
deleted when the Ruby instance is garbage collected. So it can be set to
false when the Smoke destructor callback tells the QtRuby runtime that the
C++ instance has been deleted. That will stop it from being deleted twice.

-- Richard



More information about the Kde-bindings mailing list