If your vector holds homogenous numeric data, you're much better off creating an array.array
to transfer the values to Python.
Unlike a list, an array internally stores its values as a contiguous array of native C values, but otherwise provides a Pythonic list-like interface. It use minimizes memory footprint and enables you to actually use a single memcpy
call to efficiently transfer the data. Here is an example:
PyObject *
vec_to_array(std::vector<double>& vec)
{
static PyObject *single_array;
if (!single_array) {
PyObject *array_module = PyImport_ImportModule("array");
if (!array_module)
return NULL;
PyObject *array_type = PyObject_GetAttrString(array_module, "array");
Py_DECREF(array_module);
if (!array_type)
return NULL;
// array.array('d', [0.0])
single_array = PyObject_CallFunction(array_type, "c[d]", 'd', 0.0);
Py_DECREF(array_type);
if (!single_array)
return NULL;
}
// extra-fast way to create an empty array of count elements:
// array = single_element_array * count
PyObject *pysize = PyLong_FromSsize_t(vec.size());
if (!pysize)
return NULL;
PyObject *array = PyNumber_Multiply(single_array, pysize);
Py_DECREF(pysize);
if (!array)
return NULL;
// now, obtain the address of the array's buffer
PyObject *buffer_info = PyObject_CallMethod(array, "buffer_info", "");
if (!buffer_info) {
Py_DECREF(array);
return NULL;
}
PyObject *pyaddr = PyTuple_GetItem(buffer_info, 0);
void *addr = PyLong_AsVoidPtr(pyaddr);
// and, finally, copy the data.
if (vec.size())
memcpy(addr, &vec[0], vec.size() * sizeof(double));
return array;
}
Enhancing this with template specializations to support other primitive types is left as an exercise for the reader.