C API: Error allocating / deallocating memory for array

70 Views Asked by At

I'm in the process of implementing an API for C. The code base itself is purely written in C++ and I only plan to offer said interface for any consumer using C. The interface is defined in a .h file, whereas the implementation itself is written in C++. I've read multiple times that using C++ to implement a C interface is not the best idea, but it works great in my case.

Anyway the header definition looks similar to this:

extern 'C' {
  typedef struct Person {
    const char *name;
    uint32_t age;
    uint32_t post_code;
  } Person;

  typedef struct PersonArray {
    Person *person;
    size_t size;
  } PersonArray;

  PersonArray *create(size_t size);
  void destroy(PersonArray *array);
  int fillArray(PersonArray *array);
  
}

I'd like the consumer to retrieve a handle for PersonArray, which contains an array of Person structure, allocated with the size passed to the create() function.

Since the implementation is in C++ I've tried to allocate the memory the following way:

static inline Person convert(const otherNamespace::Person &o_person) {
  Person p{};
  p.name = o_person.name;
  p.age = o_person.age;
  p.post_code = o_person.post_code;
  return p;
}

PersonArray *create(size_t size) {
  if (size <= 0) {
    return nullptr;
  }

  PersonArray *array = new PersonArray();
  array->size = size;

  array->person = new Person[size]
  return array;
}

void destory(PersonArray *array) {
  delete array;
}

int fillArray(PersonArray *array) {
  if (array == nullptr) {
    return 1;
  }
  auto data = // retrieve std::vector<otherNamespace::Person> via RPC
  for (auto i{0U}; i < array->size; i++) {
    array->person[i] = convert(data.at(i);
  }
  
  return 0;
}

Unfortunately, this approach does not seem to work correctly, because when using a memchecker like valgrind, there are still blocks on the heap that are not correctly deallocated. I suppose the line new Person[size] does not get deallocated.

Any idea how to fix this memory leak? Or is there another design which would be better suited for this specific use case? If possible, I would really like to keep the implementation in C++.

1

There are 1 best solutions below

2
carce-bo On

You must use delete on person before array, but since it was allocated with new [] you must delete it with delete [].

void destroy(PersonArray *array) {
  if (array) {
      if (array->person) {
          delete [] array->person;
      }
      delete array;
  }
}