当前位置: 首页 > 面试题库 >

如何在不复制对象的情况下公开将C ++对象返回给Python的函数?

从景曜
2023-03-14
问题内容

在另一个问题中,我学习了如何通过复制对象来公开将C++对象返回给Python的函数。必须执行复制似乎不是最佳选择。如何不复制就返回对象?即如何直接访问self.thisptr.getPeaks(data)in中返回的峰PyPeakDetection.getPeaks(在peak_detection_.pyx 中定义)?

peak_detection.hpp

#ifndef PEAKDETECTION_H
#define PEAKDETECTION_H

#include <string>
#include <map>
#include <vector>

#include "peak.hpp"


class PeakDetection
{
    public:
        PeakDetection(std::map<std::string, std::string> config);
        std::vector<Peak> getPeaks(std::vector<float> &data);

    private:
        float _threshold;               
};

#endif

peak_detection.cpp

#include <iostream>
#include <string>

#include "peak.hpp"
#include "peak_detection.hpp"


using namespace std;


PeakDetection::PeakDetection(map<string, string> config)
{   
    _threshold = stof(config["_threshold"]);
}

vector<Peak> PeakDetection::getPeaks(vector<float> &data){

    Peak peak1 = Peak(10,1);
    Peak peak2 = Peak(20,2);

    vector<Peak> test;
    test.push_back(peak1);
    test.push_back(peak2);

    return test;
}

峰值

#ifndef PEAK_H
#define PEAK_H

class Peak {
    public:
        float freq;
        float mag;

        Peak() : freq(), mag() {}
        Peak(float f, float m) : freq(f), mag(m) {}
};

#endif

peak_detection_.pyx

# distutils: language = c++
# distutils: sources = peak_detection.cpp

from libcpp.vector cimport vector
from libcpp.map cimport map
from libcpp.string cimport string

cdef extern from "peak.hpp":
    cdef cppclass Peak:
        Peak()
        Peak(Peak &)
        float freq, mag


cdef class PyPeak:
    cdef Peak *thisptr

    def __cinit__(self):
        self.thisptr = new Peak()

    def __dealloc__(self):
        del self.thisptr

    cdef copy(self, Peak &other):
        del self.thisptr
        self.thisptr = new Peak(other)

    def __repr__(self):
        return "<Peak: freq={0}, mag={1}>".format(self.freq, self.mag)

    property freq:
        def __get__(self): return self.thisptr.freq
        def __set__(self, freq): self.thisptr.freq = freq

    property mag:
        def __get__(self): return self.thisptr.mag
        def __set__(self, mag): self.thisptr.mag = mag


cdef extern from "peak_detection.hpp":
    cdef cppclass PeakDetection:
        PeakDetection(map[string,string])
        vector[Peak] getPeaks(vector[float])

cdef class PyPeakDetection:
    cdef PeakDetection *thisptr

    def __cinit__(self, map[string,string] config):
        self.thisptr = new PeakDetection(config)

    def __dealloc__(self):
        del self.thisptr

    def getPeaks(self, data):
        cdef Peak peak
        cdef PyPeak new_peak
        cdef vector[Peak] peaks = self.thisptr.getPeaks(data)

        retval = []

        for peak in peaks:
            new_peak = PyPeak()
            new_peak.copy(peak) # how can I avoid that copy?
            retval.append(new_peak)

        return retval

问题答案:

如果您拥有现代的C ++编译器并且可以使用右值引用,请移动构造函数和std ::
move,这非常简单。我认为最简单的方法是为向量创建Cython包装器,然后使用move构造函数来掌握向量的内容。

显示的所有代码都在peak_detection_.pyx中。

先包好std::move。为了简单起见,我只包装了我们想要的一种情况(vector<Peak>),而不是弄乱模板。

cdef extern from "<utility>":
    vector[Peak]&& move(vector[Peak]&&) # just define for peak rather than anything else

其次,创建向量包装器类。这定义了像列表一样访问它所必需的Python函数。它还定义了一个函数来调用移动分配运算符

cdef class PyPeakVector:
    cdef vector[Peak] vec

    cdef move_from(self, vector[Peak]&& move_this):
        self.vec = move(move_this)

    def __getitem__(self,idx):
        return PyPeak2(self,idx)

    def __len__(self):
        return self.vec.size()

然后定义包装的类Peak。这与您的其他类稍有不同,因为它不拥有Peak包装的内容(向量包含)。否则,大多数功能保持不变

cdef class PyPeak2:
    cdef int idx
    cdef PyPeakVector vector # keep this alive, since it owns the peak rather that PyPeak2

    def __cinit__(self,PyPeakVector vec,idx):
        self.vector = vec
        self.idx = idx

    cdef Peak* getthisptr(self):
        # lookup the pointer each time - it isn't generally safe
        # to store pointers incase the vector is resized
        return &self.vector.vec[self.idx]

    # rest of functions as is

    # don't define a destructor since we don't own the Peak

最后实施 getPeaks()

cdef class PyPeakDetection:
    # ...    
    def getPeaks(self, data):
        cdef Peak peak
        cdef PyPeak new_peak
        cdef vector[Peak] peaks = self.thisptr.getPeaks(data)

        retval = PyPeakVector()
        retval.move_from(move(peaks))

        return retval

替代方法:

如果Peak是平凡的,你可以去那里你调用一个方法movePeak而上的向量,为您建造PyPeak秒。对于这种情况,您在此处移动和复制将等同于`Peak。

如果您不能使用C 11功能,则需要稍微更改一下接口。不用让C

getPeaks函数返回向量,而是将一个空的向量引用(由拥有PyPeakVector)作为输入参数并写入其中。其余的大部分包装都保持不变。



 类似资料:
  • 问题内容: 我正在尝试使用Luaj + Java构建控制器。我有以下java类 以及控制器的以下lua脚本: 理想情况下,我想定义一个控制器(用lua编写),在其中我将保留程序的所有逻辑,并且我希望将该控制器的API公开给我的Java代码。我正在尝试使用以下方法: 我无法将对象传递给LuaValue。如何将Java对象传递给lua脚本? PS:通常,在使用Java和嵌入式脚本时,人们会将功能捆绑在

  • 但是当我输入一个cast时:它很好。演员阵容是我想要防止的,但这也限制了儿童建设者使用他们的特殊方法。最后一件事是有意义的,因为泛型类型只在运行时知道,但我不知道如何编写它,以便它在编译时工作。 谢谢你!

  • 但我想把它胖箭头化: 除了我得到一个错误,因为在胖箭头后面的意味着返回未定义的代码块(除非您显式地某些东西)。至少我一开始是这么想的。但我认为现在被绑定到胖箭头函数,现在是。 所以我试着这样做: 所以我想我有两个问题我很好奇。首先,从一个简单的语句胖箭头函数返回对象的惯用方法是什么?其次,如何返回对周围上下文的对象有引用的对象?

  • 我正在实现一个排序列表类,在这个类中,我将对任何类型的对象进行排序,所以现在我想测试对象是否具有可比性, 我用这段代码覆盖了compareTo()方法:- 所以现在我需要给这些对象分配数字,像这样 但它总是给我一个例外:- 线程“main”中出现异常Java . lang . classcastexception:Java . lang . integer不能转换为java.lang.String

  • 假设我有这个方法: 我想调用这个方法,获取字符串,将该字符串转换为整数7,然后以非阻塞方式返回该整数。我该怎么做? 我试过这个,但是函数阻塞(同步): 我尝试使用代替(异步): 但是我得到了这个错误:<代码>类型不匹配:无法从int转换为Mono 那我该怎么办?

  • 我正在使用一个PHP库将一个文件上传到我的bucket中。我已经将ACL设置为public read write,它可以正常工作,但文件仍然是私有的。 我发现如果我把被授权人改成所有人,文件就会公开。我想知道的是,如何将bucket中所有对象的默认grante设置为“Everyone”。或者有没有另一种默认公开文件的解决方案? 我使用的代码如下: