所以我有一个如下所示的struct
,我想创建一个该结构的数组并为其分配内存(使用malloc
)。
typedef struct {
float *Dxx;
float *Dxy;
float *Dyy;
} Hessian;
我的第一直觉是为整个结构分配内存,但我相信内部数组(Dxx
、Dxy
、Dyy
)不会被分配。如果我一个接一个地分配内部数组,那么数组的结构将是未定义的。现在我认为我应该为内部数组分配内存,然后为结构数组分配内存,但这对我来说似乎是错误的。我应该如何解决这个问题?
在这种情况下,我需要使用malloc
而不是new
/delete
的逻辑,因为我必须在cuda中执行此操作,并且cuda中的内存分配是使用cudaMalloc
完成的,这有点类似于malloc
。
在C++中,您根本不应该使用malloc
,而应该使用new
和delete
,如果实际需要。从您提供的信息来看,事实并非如此,因为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
。
这似乎是可以使用 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;
你永远不应该在 c++ 中使用 malloc。
为什么?
new
将确保您的类型将调用其构造函数。虽然malloc
不会调用构造函数。new
关键字也更安全类型,而malloc
根本不是类型安全的。
正如其他答案所指出的,在 c++ 中应避免使用malloc
(甚至new
)。无论如何,正如您要求的那样:
在这种情况下,我需要使用
malloc
而不是new
/delete
的逻辑,因为我必须在cuda中执行此操作...
在这种情况下,您必须首先为Hessian
实例分配内存,然后遍历它们并为每个Dxx
、Dxy
和Dyy
分配内存。我将为此创建一个函数,如下所示:
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
实例并首先Dxy
和Dyy
释放每个Dxx
,然后释放存储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
而不是手动分配和取消分配(强烈建议这样做),您可以为其编写一个自定义分配器以使用它cudaMalloc
和cudaFree
如下所示:
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;