将 malloc/realloc 用于类/结构数组,包括 std 向量 [英] Using malloc/realloc for array of classes/structs including std vector

查看:26
本文介绍了将 malloc/realloc 用于类/结构数组,包括 std 向量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个关于 malloc/realloc 内存的问题,它将包含一个包含 std 向量的类/结构数组(我尝试了结构和类,但问题仍然存在)成员.我知道我可以通过使用 new 和 std 数组容器类来规避这个问题.但是,我想更好地理解为什么当我使用 realloc 而不是 malloc 时以下小代码会崩溃(因为我在将较大的代码项目从 C 转换为 C++ 的上下文中遇到了这个问题).似乎我也不一定能在类/结构中设置向量的初始大小(有些编译器允许有些不允许..)-那么类中的向量是什么-舒适的指针?

I have a question wrt malloc/realloc memory that will contain an array of class/struct (i tried both struct and class the issue remains) members that include std vectors. I know I can circumvent the problem by using new and std array container class. However, I'd like to better understand why the following little code crashes when I use realloc instead of malloc (as I encountered this problem in the context of transitioning a larger code project from C to C++). It also seems that I cannot necessarily set an initial size of a vector in a class/struct (some compilers allow some don't ..)- so what is a vector in a class - a comfortable pointer?

谢谢,凯

#include <stdlib.h>
#include <limits.h>
#include <float.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <sys/types.h>
#include <vector>
/* mpic++ -O3 -ffast-math -pedantic vec-alloc.cpp -o vec-alloc */

using namespace std;

class float_vector{
public:
  double x;
  double y;
  double z;
  float_vector() : x(0), y(0), z(0) {};
};


class voxel{
public:
  float_vector   x;
  vector<double> y;

  voxel() : x() {};
};

int main(){

  int i;
  double d =1.111;
  voxel v0, *Comp, *Comp2;

  /* dynamically allocate memory */
  Comp= (voxel*)malloc(10*sizeof(voxel));
  for(i=0;i<10;++i) Comp[i] = v0;
  printf("malloc done\n");

  /* dynamically re-allocate memory */
  Comp2= (voxel*)malloc(sizeof(voxel));  
  printf("realloc done\n");
  for(i=0;i<10;++i){
    Comp2 =(voxel*)realloc(&Comp2[0], (i+1)*sizeof(voxel));
    Comp2[i] = v0;
  }  

  printf("realloc done\n");

  for(i=0;i<10;++i) Comp[i].y.push_back(d);
  for(i=0;i<10;++i) printf("%lf\n",Comp[i].y[0]);

  for(i=0;i<10;++i) Comp2[i].y.push_back(d); // this crashes
  for(i=0;i<10;++i) printf("%lf\n",Comp2[i].y[0]);

  return 1;
} 

推荐答案

如果将 malloc() 与非 POD 类一起使用,则必须调用构造函数(通过放置 new) 和手动析构函数.

If you use malloc() with non-POD classes, you must call constructors (via placement new) and destructors manually.

使用未正确构造的对象会导致未定义行为,这通常意味着指针会崩溃.

Using an object which was not constructed properly results in undefined behavior, which often means a crash when it comes to pointers.

显然,在没有适当销毁对象的情况下为对象释放内存也会导致 UB.

Obviously, freeing a memory for object without a proper destruction of it causes UB too.

您的代码必须如下所示:

Your code must look like this:

MyClass *arr = (MyClass *) malloc(10 * sizeof (MyClass));

for (int i = 0; i < 10; i++)
    new (arr + i) MyClass; // This line calls constructors

// Do something with the array here

for (int i = 0; i < 10; i++)
    arr[i].~MyClass(); // This line calls destructors.

free(arr);

<小时>

这个要求也意味着你不能将 realloc() 用于非 POD 类型,因为它不会为你调用旧数组的析构函数和新数组的构造函数.


This requirement also means that you can't use realloc() with non-POD types, because it wont call destructors for the old array and contructors for the new one for you.

手动重新分配代码可能如下所示:

Manual reallocation code might look like this:

MyClass *new_ptr = (MyClass *) malloc(new_size * sizeof (MyClass));

for (int i = 0; i < new_size; i++)
    new (new_ptr + i) MyClass((MyClass &&) old_ptr[i]);

for (int i = new_size; i < old_size; i++)
    new (new_ptr + i) MyClass;

for (int i = 0; i < old_size; i++)
    old_ptr[i].~MyClass();

free(old_ptr);

<小时>

请记住,上面的代码并不是真正的异常安全.如果构造函数抛出异常并且您捕获了它,那么您要确保正确销毁已构造的对象.谢谢@SteveJessop.

现在当你明白为什么在 C++ 中通常应该避免 malloc()/free() 时,我希望你会回到更安全的状态new/delete,它为你完成所有的构建和销毁.

Now when you understand why malloc()/free() usually should be avoided in C++, I hope you'll return to a lot more safe new/delete, which do all that construction and destruction for you.

这篇关于将 malloc/realloc 用于类/结构数组,包括 std 向量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆