如何为数组结构的数组分配内存

时间:2017-08-29 13:20:22

标签: c++ cuda malloc

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

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

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

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

3 个答案:

答案 0 :(得分:3)

在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

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

答案 1 :(得分: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 类型安全。

答案 2 :(得分:1)

正如其他答案所指出的那样,应避免使用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 ,然后解除分配存储Hessian实例的块:

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;