3

I am following the documentation here: http://www.swig.org/Doc3.0/Library.html#Library_stl_cpp_library to write a wrapper to a simple example code involving vectors.

Here is the header file:

### word.h ###
#include<string>
#include<vector>

class Word{
public:
    Word(std::string word, int numWords, std::vector<double> &values);
    ~Word();

    void updateWord(std::string newWord);
    std::string getWord();
    void processValues();

private:
    std::string theWord;
    int totalWords;
    std::vector<double> values;
};

And the source file:

### word.cpp ###
#include "word.h"
#include <cfloat>
#include <cmath>
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <time.h>

Word::Word(std::string word, int numWords, std::vector<double> &values) :
    theWord(word), totalWords(numWords), values(values){
    // TODO: constructor
}

Word::~Word() {
    // TODO: destructor
}

void Word::updateWord(std::string newWord) {
    this->theWord = newWord;
}

std::string Word::getWord() {
    return this->theWord;
}

void Word::processValues() {
    values.resize(totalWords);
    // do something with values here
}

/*  
    rest of the code that uses the other imports
*/

Here is the interface file:

### word.i ###
%module word
%{
#include "word.h"
%}

%include "std_string.i"
%include "std_vector.i"

namespace std {
    %template(vectord) vector<double>;
}

%include "word.h"

My compilation steps are as follows:

swig -c++ -python word.i
g++ -c -fpic word.cpp word_wrap.cxx -I/usr/include/python2.7
g++ -shared word.o word_wrap.o -o _word.so -lstdc++

The compilation goes through without any errors. However, on trying to create the object in Python I get the following error:

In [1]: import word

In [2]: w = word.Word('test', 10, [10.2])
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-2-ee2e5c406fd9> in <module>()
----> 1 w = word.Word('test', 10, [10.2])

/home/anarayan/workspace/swig-learn/word.pyc in __init__(self, word, numWords, values)
    276 
    277     def __init__(self, word, numWords, values):
--> 278         this = _word.new_Word(word, numWords, values)
    279         try:
    280             self.this.append(this)

TypeError: in method 'new_Word', argument 3 of type 'std::vector< double,std::allocator< double > > &'

A bit of searching online leads me to believe that using the template in the SWIG definition solves this problem.

However, in my case it hasn't. Could you please point me in the right direction?

okkhoy
  • 1,298
  • 3
  • 16
  • 29

1 Answers1

2

It doesn't work because you passing the vector by reference. If you instead pass by value or by const reference SWIG knows what to do and generates the correct code. Simply changing the type in the declaration and defintion of

Word(std::string word, int numWords, std::vector<double> const &values);

is sufficient.

$ swig -c++ -python word.i
$ g++ -c -fpic word.cpp word_wrap.cxx -I/usr/include/python2.7
$ g++ -shared word.o word_wrap.o -o _word.so -lstdc++
$ python
Python 2.7.13 (default, Nov 24 2017, 17:33:09) 
[GCC 6.3.0 20170516] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import word
>>> w = word.Word('test', 10, [10.2])

In this case you can apply the above adjustments because you don't need values to be a bare reference. If a reference is needed more work is required and you have to write your own typemap (and probably your own container).

Henri Menke
  • 10,705
  • 1
  • 24
  • 42
  • If I really wanted to use (and modify) a std::vector in my C++ function without copying, what alternatives would I have ? Raw pointer to std::vector ? shared_ptr to std::vector ? (I am also asking [here](https://stackoverflow.com/a/58845629/4669135)) – Gabriel Devillers Apr 21 '20 at 16:27
  • 1
    @GabrielDevillers You can't view the Python list through a C++ vector, because the vector by definition owns its memory. If you are using NumPy arrays instead of lists, you can use the `numpy.i` SWIG bindings to get a pointer to the underlying array and modify it in place: https://numpy.org/doc/stable/reference/swig.interface-file.html#in-place-arrays – Henri Menke Apr 21 '20 at 22:41