[PyQt] DOUBTT

Chris Kaynor ckaynor at zindagigames.com
Wed Jul 23 23:36:58 BST 2014


On Wed, Jul 23, 2014 at 2:59 PM, Amey Patil <amey.patil at sjsu.edu> wrote:

> Hi,
> I am at the basic level in using sip wrapper in python. I have written a
> small library in c++ and wrapping it in sip for execution in Python.
> Copy pasting my entire files for better understanding. Also pasting the
> output from the terminal, the behaviour i am getting is completely
> unexpected, can you please look into it...
>

I've included some options. As I do not know your overall skill level in
C++/Python, I have included quite a bit of detail overall.

Without knowing your full use cases, in addition to sip, you may want to
look at Cython (compiles a very Python-like language to C code), using the
Python C APIs directly (a fairly direct replacement for sip), or using PyPy
(which has a JIT compiler for Python to speed it up). Each of the four
options has its own benefits and drawbacks.


>
> *word.h:*
>
> class Word
> {
>
> public:
>     int integer;
>     const char *name;
>     Word();
>     void set_name(const char *a);
>     void reset_name();
>     const char *get_name();
> };
>
> *word.cpp:*
>
> #include <iostream>
> #include "word.h"
>
> using namespace std;
>
> Word::Word(){
>     name = "PyQt";
>
> }
>
> void Word::set_name(const char *a){
>     cout << "parameter passed to set_name is " << a << endl;
>     cout << "name before set_name is " << name << endl;
>     name = a;
>

This line is probably your problem. You'll probably want to copy the string
"a" into a buffer rather than assign the pointer. Without this, as soon as
the string pointed to by "a" is deallocated, the name parameter becomes
invalid. This is known as a dangling pointer, and can cause odd bugs, such
as getting random values or crashing when accessing.

For cases where a will be a constant, hard-coded, C variable (such as for
reset_name below), the string will typically be held in a data section that
will live for as long as the program runs, and thus it will work. If you
were to call set_name from a value read from a file, however, you'd likely
find the name will change later, similar to the sip-wrapped code.

There are a few common ways to deal with this in C:
1) Use a constant size char buffer, such as, in the class use "char
name[32]" rather than "const char *name", then use strcpy to copy the new
value into the fixed-size buffer. Be aware of the issues with copying more
than the size of the buffer!
2) Use a dynamically allocated array: use the malloc function or new
operator to make the name buffer based on the length of the string set,
then do the strcpy as above. You have to be sure to properly free the
memory when destroying the Word object or when new memory is allocated for
name. You can also use a string class such as std::string (C++ standard
library) which does this internally, with safety mechanisms.
3) Keep a reference to the Python string object. I do not know how to make
sip do this (I haven't really used sip much). This will keep the memory
valid, however you also have to be sure that when the reference is released
when the name is changed again or the Word object is destroyed.


>     cout << "name after set_name is " << name << endl;
> }
>

>
void Word::reset_name(){
>     cout << "name before reset_name is " << name << endl;
>     const char *x = "Epics";
>     name = x;
>
    cout << "name after reset_name is " << name << endl;
> }
>
> const char *Word::get_name(){
>     cout << "name before get_name is " << name << endl;
>     return name;
> }
>
> *word.sip:*
>
> %Module word
>
> class Word
> {
>
> %TypeHeaderCode
> #include <word.h>
> %End
>
> public:
>     int integer;
>     const char *name;
>     Word();
>     void set_name(const char *a);
>     void reset_name();
>     const char *get_name();
> };
>
> *Output in Python (Terminal):*
>
> >>> import word
> >>> w = word.Word()
>  >>> w.get_name()
> name before get_name is PyQt
> 'PyQt'
> >>> w.set_name("Amey")
> parameter passed to set_name is Amey
> name before set_name is PyQt
> name after set_name is Amey
>

After the set_name call returns, the Python object "Amey" goes out of
scope, and Python may garbage collect it. Often, this happens immediately,
however for various reasons it could be kept around for a while. Try
assigning "Amey" to a variable, then pass that variable into the function;
the following code will probably work, until you replace or delete the
variable, or the variable goes out of scope. Such an assignment will be
similar to keeping a reference around in the C code (as mentioned above, I
do not know how to do so with sip).


> >>> w.get_name()
> name before get_name is
> ''
>

You've just read the memory that used to point to the string "Amey", but
has been reused for other reasons. The new reason may change each time, and
eventually the memory may be completely freed at the OS level, or used for
a purpose for which you cannot read the memory, at which point you will get
a crash.


> >>> w.reset_name()
> name before reset_name is <stdin>
> name after reset_name is Epics
> >>> w.get_name()
> name before get_name is Epics
> 'Epics'
>
> PROBLEMS:
> 1. It won't print the output when i call get_name() after calling
> set_name().
> 2. As you can see in the output, I am editing nothing between the
> highlighted lines, still the output shows nothing in one while <stdin> in
> other.
>
> Please tell me what's wrong.
>
> Looking forward for your reply,
>
> Sincere Regards,
> Amey Patil
>
> _______________________________________________
> PyQt mailing list    PyQt at riverbankcomputing.com
> http://www.riverbankcomputing.com/mailman/listinfo/pyqt
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.riverbankcomputing.com/pipermail/pyqt/attachments/20140723/915bf8e2/attachment.html>


More information about the PyQt mailing list