2

I am new to C++, so apologies for any 'silly' mistakes.

I have created a shared object in C++ for use in Python. However, when I try to call this function in Python, the kernel crashes.

The C++ file is as follows:

#include <cmath>
#include <iostream>
#include <list>
#include <vector>

using namespace std;

extern "C" 
{
    vector<int> cplusplus(int n=3,int maximum=1000)
    {          
        int i,j,order,m,i1,i2,mag;
        vector<int> output(0);

        i=1;
        j=0;

        while (i/maximum<=1)
        {
            i=10*i;
            j=j+1;
        } 

        m=j-1;

        for (i1=1; i1<m+2; i1++)
        {
            mag=pow(10,(i1-1));
            i=0;

            while (i+mag*(n+1)<=maximum)
            {
                for (i2=i+mag*n; i2<i+mag*(n+1); i2++)
                {
                    output.push_back(i2-1);
                }
                i=i+10*mag;
            } 

            if(i+mag*(n+1)>maximum)
            {
                for (i2=i+mag*n; i2<maximum+1; i2++)
                {
                    output.push_back(i2-1);
                }   
            }
        } 

        return output;
    }
}

I create the .so file using:

g++ -shared -o cplusplus.so cplusplus.cpp

and I call the C++ function in Python using:

import ctypes

cpp=ctypes.cdll.LoadLibrary('/Users/.../cplusplus.so')
print cpp.cplusplus(n=3,maximum=1000)

The function, when returned correctly, should return a vector of all the numbers between 1 and 1000 containing a 3 (i.e. 3,13,23,30,31,...). Currently, however, the Python kernel crashes.

I would imagine it's something to do with my use of vectors or a memory leak in the C++ file.

Thanks in advance for any help!

1
  • 1
    This is ctypes not cpptypes. ctypes can't handle a vector<int>. You must have C data types. Commented Apr 9, 2017 at 20:51

3 Answers 3

1

ctypes doesn't understand C++ types, so here is a version of the function that uses only C types in the function interface. The result buffer has to be pre-allocated and the number of elements passed in by address. The function updates the number of elements with the length of the computed vector, then returns 1 (success) if it could copy those elements into the result buffer, else returns 0 (fail).

Note that the code algorithm is incorrect and returns the wrong answer, but ctypes works.

#include <cmath>
#include <iostream>
#include <list>
#include <vector>
using namespace std;

extern "C"
{
    __declspec(dllexport) int cplusplus(int n, int maximum, int* result, size_t* pLength)
    {
        int i, j, order, m, i1, i2, mag;
        vector<int> output(0);

        i = 1;
        j = 0;

        while(i / maximum <= 1)
        {
            i = 10 * i;
            j = j + 1;
        }

        m = j - 1;

        for(i1 = 1; i1 < m + 2; i1++)
        {
            mag = pow(10, (i1 - 1));
            i = 0;

            while(i + mag * (n + 1) <= maximum)
            {
                for(i2 = i + mag * n; i2 < i + mag * (n + 1); i2++)
                    output.push_back(i2 - 1);

                i = i + 10 * mag;
            }

            if(i + mag * (n + 1) > maximum)
            {
                for(i2 = i + mag * n; i2 < maximum + 1; i2++)
                    output.push_back(i2 - 1);
            }
        }

        if(output.size() > *pLength)
        {
            *pLength = output.size();
            return 0; // fail
        }

        *pLength = output.size();
        memcpy(result, output.data(), output.size() * sizeof(int));
        return 1; // success
    }
}
>>> from ctypes import *
>>> lib = CDLL('test')
>>> lib.cplusplus.argtypes = c_int,c_int,POINTER(c_int),POINTER(c_size_t)
>>> lib.cplusplus.restype = c_int
>>> arr = (c_int * 1000)()
>>> size = c_size_t(1000)
>>> lib.cplusplus(3,1000,arr,byref(size))
1
>>> size
c_ulonglong(300)
>>> list(arr[:size.value])
[2, 12, 22, 32, 42, 52, 62, 72, 82, 92, 102, 112, 122, 132, 142, 152, 162, 172, 182, 192, 202, 212, 222, 232, 242, 252,
262, 272, 282, 292, 302, 312, 322, 332, 342, 352, 362, 372, 382, 392, 402, 412, 422, 432, 442, 452, 462, 472, 482, 492,
502, 512, 522, 532, 542, 552, 562, 572, 582, 592, 602, 612, 622, 632, 642, 652, 662, 672, 682, 692, 702, 712, 722, 732,
742, 752, 762, 772, 782, 792, 802, 812, 822, 832, 842, 852, 862, 872, 882, 892, 902, 912, 922, 932, 942, 952, 962, 972,
982, 992, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 229, 230, 231, 232,
233, 234, 235, 236, 237, 238, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 429, 430, 431, 432, 433, 434, 435, 436,
437, 438, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 629, 630, 631, 632, 633, 634, 635, 636, 637, 638, 729, 730,
731, 732, 733, 734, 735, 736, 737, 738, 829, 830, 831, 832, 833, 834, 835, 836, 837, 838, 929, 930, 931, 932, 933, 934,
935, 936, 937, 938, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318,
319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342,
343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366,
367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390,
391, 392, 393, 394, 395, 396, 397, 398]
>>> size = c_size_t(200) # too small
>>> lib.cplusplus(3,1000,arr,byref(size))
0
>>> size
c_ulonglong(300)
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you very much! The incorrect statement in the algorithm was output_push.back(i2-1). It should be output_push.back(i2) instead.
0

I'm wondering whether n and maximum are actual variables. Just try:

Print cpp.cplusplus ()

Try to build a method that display your vector in c++. So that you are not mixing printing langage methodes.

1 Comment

I'm afraid the kernel still crashes using this.
0

You need to tell python what the input and return types of you function are Docs. I pretty sure that std::vector is not part of the options, the options are listed in the docs.

This is not the fastest of best practice option What I did to get started, was to serialize your input to json, and pass them as a char_p to the shared library, and then cast them in c++, and return another char_p... But of course this is not the fastest or best option.

(If you did define the types correctly, edit your post, and I will remove this answer)

Comments

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.