如何对数组使用 shared_ptr 和 make_shared?

How to use shared_ptr and make_shared with arrays?

我想使用 C++ shared_ptr 来替代原始 C 指针。作为一个简单的示例,以下代码似乎按预期工作:

from libcpp.memory cimport shared_ptr, allocator

cdef shared_ptr[double] spd 
cdef allocator[double] allo
spd.reset(allo.allocate(13))

此处大小选择为13,但一般在编译时是不知道的。 我不确定这是否正确,但我没有遇到任何错误(还没有内存泄漏和段错误)。我很好奇 make_shared.

是否有更优的解决方案

但我不能使用 C++11 数组,因为 Cython 不允许文字作为模板,例如像

cdef shared_ptr[array[double]] spd = make_shared[array[double,13]]()

和应该与 C++20 编译器(例如 gcc 10)一起工作的“普通”数组以某种方式引起问题:

# Cython error "Expected an identifier or literal"
cdef shared_ptr[double[]] spd = make_shared[double[]](3)    

# Can't get ptr to work
ctypedef double[] darr
cdef shared_ptr[darr] spd = make_shared[darr](13)
cdef double* ptr = spd.get()    # or spd.get()[0] or <double*> spd.get()[0] or ...

分配器解决方案是正确且最好的解决方案还是有其他方法?

这是我要处理的

cdef extern from *:
    """
    template <typename T>
    struct Ptr_deleter{
        size_t nn;
        void (*free_ptr)(T*, size_t);
        Ptr_deleter(size_t nIn, void (*free_ptrIn)(T*, size_t)){
            this->nn = nIn;
            this->free_ptr = free_ptrIn;
        };
        void operator()(T* ptr){
            free_ptr(ptr, nn);
        };
    };
    template <typename T>
    std::shared_ptr<T> ptr_to_sptr (T* ptr, size_t nn, void (*free_ptr)(T*, size_t)) {
        Ptr_deleter dltr(nn,  free_ptr);
        std::shared_ptr<T> sp (ptr, dltr);
        return sp;
    };
    """
    shared_ptr[double] d_ptr_to_sptr "ptr_to_sptr"(double* ptr, size_t nn, void (*free_ptr)(double*, size_t) nogil) nogil

cdef void free_d_ptr(double* ptr, size_t nn) nogil:
    free(ptr)

cdef shared_ptr[double] sp_d_empty(size_t nn) nogil:
    return d_ptr_to_sptr(<double*> nullCheckMalloc(nn*sizeof(double)), nn, &free_d_ptr)

我的理解是,处理 malloced 数组的“正确”方法是像我一样使用自定义删除器。我个人更喜欢坚持使用 somewhat-raw C 指针(double* 而不是 double[] 或其他东西),因为它在 Cython 和我的项目中更自然。

我认为了解如何针对更复杂的数据类型更改 free_ptr 相当容易。对于简单的数据类型,它可以用更少的行和更少的复杂性来完成,但我希望有相同的基础。

我喜欢我的解决方案,因为我可以将现有的 Cython/C 代码原始指针“包装”在 shared_ptr.

在使用 C++(尤其是 C++20 等较新的标准)时,我认为逐字代码通常是必需的。但是我有意在 Cython 中定义了 free_d_ptr,因此可以很容易地使用现有的 Cython 代码来处理对 free/clear/whatever 数组所做的实际工作。

我没有让 C++11 std::arrays 工作,而且它在 Cython 中显然不是一般的“正确”可能(参见 )。

我也没有得到 double[] 或类似的工作(在 C++20 中是可能的),但是对于逐字的 C++ 代码,我认为这在 Cython 中应该是可行的。无论如何,我更喜欢 C-like pointers/arrays