【问题标题】:how to allocate memory for arrays of structure of arrays如何为数组结构的数组分配内存
【发布时间】:2018-02-06 23:30:41
【问题描述】:

所以我有一个struct,如下所示,我想创建一个该结构的数组并为其分配内存(使用malloc)。

typedef struct {
    float *Dxx;
    float *Dxy;
    float *Dyy;
} Hessian; 

我的第一直觉是为整个结构分配内存,但是我相信内部数组(DxxDxyDyy)不会被分配。如果我一一分配内部数组,那么数组的结构将是未定义的。现在我认为我应该为内部数组分配内存,然后为结构数组分配内存,但这对我来说似乎是错误的。我应该如何解决这个问题?

我需要在这种情况下使用malloc 而不是new / delete 的逻辑,因为我必须在 中执行此操作,并且 中的内存分配是使用cudaMalloc 完成的,即有点类似于malloc

【问题讨论】:

  • 您可以通过学习如何使用std::vector 并让 C++ 库为您完成工作来解决问题。有关更多信息,请参阅您的 C++ 书籍。
  • 首先不要在 C++ 中使用malloc。其次,为什么不使用std::vector?或者甚至std::array 如果大小是固定的并且在编译时已知?
  • C++ 中不需要typedef struct
  • 这是一个指针结构,而不是数组。
  • 当然,您可以通过多种方式做到这一点,但是在 CUDA 中使用这些结构的数组会有些复杂,并且可能不是实现最佳性能的方法。无论如何here 是 CUDA 中分配和使用结构数组的一个工作示例,其中结构具有嵌入式指针。

标签: cuda cuda c++ cuda malloc


【解决方案1】:

在 C++ 中,您根本不应该使用 malloc,而应在实际需要时使用 newdelete。根据您提供的信息,它不是,因为在 C++ 中,您还宁愿使用 std::vector(或 std::array)而不是 C 样式数组。也不需要typedef

所以我建议重写你的结构以使用向量,然后生成这个结构的向量,即:

struct Hessian {
  std::vector<float> Dxx;
  std::vector<float> Dxy;
  std::vector<float> Dyy;
}; 

std::vector<Hessian> hessianArray(2); // vector containing two instances of your struct
hessianArray[0].Dxx.push_back(1.0); // example accessing the members

使用向量大多数时候您不必担心分配问题,因为类会为您处理。 hessianArray 中包含的每个 Hessian 都会自动为您分配,存储在堆上并在 hessianArray 超出范围时销毁。

【讨论】:

    【解决方案2】:

    这似乎是可以使用 STL 容器解决的问题。关于你不会知道你可以使用std::vector的数组大小这一事实。

    它更不容易出错,更易于维护/使用标准容器自行释放资源 (RAII)。 @muXXmit2X 已经展示了如何使用它们。

    但是如果你有/想要使用动态分配,你必须首先为 X 结构数组分配空间

    Hessian *h = new Hessian[X];
    

    然后为所有结构中的所有数组分配空间

    for (int i = 0; i < X; i++)
    {
        h[i].Dxx = new float[Y];
        // Same for Dxy & Dyy
    }
    

    现在您可以访问和修改它们。也别忘了释放资源

    for (int i = 0; i < X; i++)
    {
        delete[] h[i].Dxx;
        // Same for Dxy & Dyy
    }
    delete[] h;
    

    您应该永远不要 中使用 malloc。

    为什么?

    new 将确保您的类型将调用其构造函数。而malloc 不会调用构造函数。 new 关键字也更安全,而 malloc 根本不是类型安全的。

    【讨论】:

    • 它将确保您的类型将调用其构造函数。您的意思是new,对吗?你写它的方式,听起来malloc 会调用构造函数,但它不会。
    • 可能有点误导。我已经修好了。
    【解决方案3】:

    正如其他答案所指出的, 中应避免使用malloc(甚至new)。无论如何,如你所愿:

    我需要在这种情况下使用malloc 而不是new / delete 的逻辑,因为我必须在 中执行此操作...

    在这种情况下,您必须首先为Hessian 实例分配内存,然后遍历它们并为每个DxxDxyDyy 分配内存。我会为此创建一个函数,如下所示:

    Hessian* create(size_t length) {
        Hessian* obj = (Hessian*)malloc(length * sizeof(Hessian));
    
        for(size_t i = 0; i < length; ++i) {
            obj[i].Dxx = (float*)malloc(sizeof(float));
            obj[i].Dxy = (float*)malloc(sizeof(float));
            obj[i].Dyy = (float*)malloc(sizeof(float));
        }
    
        return obj;
    }
    

    要释放您使用上述create 函数分配的内存,您必须遍历Hessian 实例并首先释放每个DxxDxyDyy,然后释放存储@987654340 的块@实例:

    void destroy(Hessian* obj, size_t length) {
        for(size_t i = 0; i < length; ++i) {
            free(obj[i].Dxx);
            free(obj[i].Dxy);
            free(obj[i].Dyy);
        }
    
        free(obj);
    }
    

    注意:使用所提供的方法会将防止内存泄漏的责任转嫁给您。


    如果您希望使用std::vector 而不是手动分配和释放(强烈推荐),您可以write a custom allocator 使用cudaMalloccudaFree,如下所示:

    template<typename T> struct cuda_allocator {
        using value_type = T;
    
        cuda_allocator() = default;
        template<typename U> cuda_allocator(const cuda_allocator<U>&) {
        }
    
        T* allocate(std::size_t count) {
            if(count <= max_size()) {
                void* raw_ptr = nullptr;
    
                if(cudaMalloc(&raw_ptr, count * sizeof(T)) == cudaSuccess)
                    return static_cast<T*>(raw_ptr);
            }
            throw std::bad_alloc();
        }
        void deallocate(T* raw_ptr, std::size_t) {
            cudaFree(raw_ptr);
        }
        static std::size_t max_size() {
            return std::numeric_limits<std::size_t>::max() / sizeof(T);
        }
    };
    
    template<typename T, typename U>
    inline bool operator==(const cuda_allocator<T>&, const cuda_allocator<U>&) {
        return true;
    }
    template<typename T, typename U>
    inline bool operator!=(const cuda_allocator<T>& a, const cuda_allocator<U>& b) {
        return !(a == b);
    }
    

    自定义分配器的使用非常简单,只需将其指定为std::vector的第二个模板参数即可:

    struct Hessian {
        std::vector<float, cuda_allocator<float>> Dxx;
        std::vector<float, cuda_allocator<float>> Dxy;
        std::vector<float, cuda_allocator<float>> Dyy;
    };
    
    /* ... */
    
    std::vector<Hessian, cuda_allocator<Hessian>> hessian;
    

    【讨论】:

      猜你喜欢
      • 2020-02-03
      • 2014-04-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-12
      • 2020-09-03
      • 1970-01-01
      相关资源
      最近更新 更多