Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
371 views
in Technique[技术] by (71.8m points)

c++ - Using malloc/realloc for array of classes/structs including std vector

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?

Thanks, Kai

#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
");

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

  printf("realloc done
");

  for(i=0;i<10;++i) Comp[i].y.push_back(d);
  for(i=0;i<10;++i) printf("%lf
",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
",Comp2[i].y[0]);

  return 1;
} 
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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.

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);

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);

And please keep in mind that above code is not really exception-safe. If a constructor throws an exception and you catch it, then you want to be sure that you properly destruct objects which were constructed. Thanks @SteveJessop.

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...