2

I am trying to use SWIG in an effort to call member functions of a C++ object from Python. Currently I have a small example class with a getter and setter to modify a member variable of the C++ class. Here is the C++ header file:

#ifndef _square_
#define _square_
#include <iostream>

class Square
{
 private:
    double x;
    double y;
    const char *name;

 public:
    void setName(const char*);
    const char* getName();
    Square() {
        name = "construct value";
    };
};
#endif

Here is the .cpp implementation file:

#include <iostream>
using namespace std;
#include "Square.h"

const char* Square::getName()
{
    return name;
}

void Square::setName(const char* name)
{
    this->name = name;
    return;
}

And the Square.i file for SWIG:

%module Square
%{
#include "Square.h"
%}

%include "Square.h"

SWIG seems to generate the Square_wrap.cxx file without issue, and the resulting object files seem to link fine:

$ swig -python -c++ Square.i
$ g++ -c -fpic Square.cxx Square_wrap.cxx -I/usr/include/python2.7
$ g++ -shared Square.o Square_wrap.o -o _Square.so

Now for some example Python to test the results:

$ cat test2.py
#!/usr/bin/python
import Square

s = Square.Square()

print s.getName()
s.setName("newnametest")
print s.getName()

If I run this through the Python interpreter everything works fine:

$ python test2.py
construct value
newnametest

But if I interactively enter in the test lines via Python's CLI, things do not work:

$ python
Python 2.7.4 (default, Apr 19 2013, 18:28:01) 
[GCC 4.7.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import Square
>>> 
>>> s = Square.Square()
>>> 
>>> print s.getName()
construct value
>>> s.setName("newnametest")
>>> print s.getName()

>>> s.getName()
'<stdin>'
>>> s.setName('newnametest')
>>> s.getName()
''
>>> s.setName("newnametest")
>>> s.getName()
''

Does Python handle a Python script file differently under the hood in comparison to the CLI, or am I somehow abusing the Python interface generated by SWIG? Any tips on how to debug or understand the issue under the hood would be much appreciated.

1 Answer 1

1

As far as I see, you are just storing the reference on the cpp file (this->name = name). It would be good to copy it, because there are high chances the string doesn't last enough and is just discarded after the function returns (and garbage collected slightly after that). This would explain why in the script it works (there is no GCollection nor anything else happens between the two calls).

Try making a copy with strdup or using std::string.

Sign up to request clarification or add additional context in comments.

3 Comments

That definitely could explain the difference, except I tried disabling the garbage collector with import gc and gc.disable() but still receive the same results. Unless there is another means, it seems like this should help preserve the state between the CLI commands.
Although you are correct: duplicating the string does fix the problem. Thanks for providing some insight! void Square::setName(const char* name) { this->name = strdup(name); return; }
@xsquared Yes, it can be many things, don't know the internals of ctypes good enough, but you need to have in mind that the value will be discarded when the call returns.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.