Cython:避免通过std :: move复制不起作用

时间:2015-04-10 22:43:49

标签: c++11 vector cython

问题

我有一个非常大的std::vector从C ++函数返回,我们称之为getVector()

现在我想在Cython中包装该函数:

cdef extern from "XY.h":
    cdef cppclass _XY:
        vector[double] getVector() except +

cdef class XY:
    cdef _XY _this

    ...

    def getVector():
        return self._this.getVector()

由于我想避免复制这个大型向量,我想使用std :: move。像这样:

cdef extern from "<utility>" namespace "std":
    vector[double] move(vector[double]) # Cython has no function templates

这以下列方式修改Cython源代码:

def getVector():
    return move(self._this.getVector())

问题

上述想法无效。 Cython(至少)产生1个载体拷贝。 我假设这是因为没有办法从向量移动,因为这已经是C ++中实际的std :: vector类的Cython包装器。

是否有其他方法可以避免任何副本?我想避免从C ++方法返回一个指针。

可能有一种方法可以定义一个存储向量的C ++包装类,然后在Cython中移动这个类,但我想知道是否有一种方法没有(或很少)修改C ++源代码。

1 个答案:

答案 0 :(得分:1)

编辑:@DavidW发出警告后,我意识到我误解了您的问题。下面的答案只是让您直接从cython使用模板化的from socket import AF_INET, SOCK_STREAM, socket, gethostname from tkinter import * from tkinter import ttk IP = gethostname() # or "127.0.0.1" PORT = 1337 root = Tk() root.title("") mainframe = ttk.Frame(root, padding="3 3 12 12") mainframe.grid(column=0, row=0, sticky=(N, W, E, S)) root.columnconfigure(0, weight=1) root.rowconfigure(0, weight=1) for child in mainframe.winfo_children(): child.grid_configure(padx=5, pady=5) root.bind('<Return>', connectionFunc) def connectionFunc(*args): # this way you dont have to close the socket. with socket(AF_INET, SOCK_STREAM) as s: s.listen() s.bind((IP, PORT)) conn, addr = s.accept() with conn: print(f"connection from: {addr}") while True: data = conn.recv(1024) if not data: break conn.sendall(data) root.mainloop() ,而无需为每种移动类型(例如,在问题中为move声明的类型)都进行明确声明。


您可以使用此辅助函数来包装std::vector<double>调用:

std::move

用法示例:

# distutils: language = c++

cdef extern from * namespace "polyfill":
    """
    namespace polyfill {

    template <typename T>
    inline typename std::remove_reference<T>::type&& move(T& t) {
        return std::move(t);
    }

    template <typename T>
    inline typename std::remove_reference<T>::type&& move(T&& t) {
        return std::move(t);
    }

    }  // namespace polyfill
    """
    cdef T move[T](T)

输出(使用# distutils: language = c++ cdef extern from *: """ #include <iostream> #define PRINT() std::cout << __PRETTY_FUNCTION__ << std::endl struct Test { Test() { PRINT(); } ~Test() { PRINT(); } Test(const Test&) { PRINT(); } Test(Test&&) { PRINT(); } Test& operator=(const Test&) { PRINT(); return *this; } Test& operator=(Test&&) { PRINT(); return *this; } }; void f(const Test&) { PRINT(); } void f(Test&&) { PRINT(); } """ cdef cppclass Test: pass cdef void f(Test) from move cimport move cdef Test t1, t2 print("# t1 = t2") t1 = t2 print("# t1 = move(t2)") t1 = move(t2) print("# f(t1)") f(t1) print("# f(move(t1))") f(move(t1)) print("# f(move(move(t1)))") f(move(move(t1))) print("# f(move(move(move(t1))))") f(move(move(move(t1)))) 和Cython 0.29.12和Python 3.7.3编译):

cythonize -3 -i test.pyx

请注意,Cython当前正在执行C ++对象的默认初始化,但是此帮助函数允许在初始化后调用移动分配。


编辑:我将此代码段打包为cymove