stclib / STC

A modern, user friendly, generic, type-safe and fast C99 container library: String, Vector, Sorted and Unordered Map and Set, Deque, Forward List, Smart Pointers, Bitset and Random numbers.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Checking memory allocation failure

Pascal-Ortiz opened this issue · comments

Hi,

C doesn't have a standard data structure library like STL in C++, so your library is very promising and attractive.

There is one point I'm not confortable with. It seems that there is no checking of the return of memory allocation. For instance, here is the source code for cvec_X_reserve (with X representing the integer type) retrieved by calling the gcc preprocessor:

static inline void cvec_i32_reserve(cvec_i32 *self, size_t cap) {
  struct cvec_rep *rep =
      ((struct cvec_rep *)((char *)((self)->data) -
                           __builtin_offsetof(struct cvec_rep, data)));
  size_t len = rep->size;
  if (cap >= len && cap != rep->cap) {
    rep = (struct cvec_rep *)realloc(rep->cap ? rep : ((void *)0),
                                     __builtin_offsetof(struct cvec_rep, data) +
                                         cap * sizeof(int));
    self->data = (cvec_i32_value_t *)rep->data;
    rep->size = len;
    rep->cap = cap;
  }
}

if rep is a null pointer, the behavoir is undefined, isn't it?

I agree that reserve could keep the old memory if realloc fails and return false. Still I don't think you will find much client code that actually checks every operation where this may happen, and have useful recovery code for all possible situations. E.g. push_back() may call reserve(), but it already returns reference to the pushed element, so what should it do on bad_alloc? In addition on some OSs, malloc returns a non-NULL pointer even when there is no more memory available.

So I think it makes sense that reserve() checks for this, but push_back() ignores if it happens. You may therefore only check after explicitely reserving some huge block of memory, and make recovery if it fails.

The reserve() and resize() functions now returns false on memory allocation failure. To be safe, reserve memory up-front if possible, and take appropriate actions if it fails. cvec, cdeq, cpque, cstack, cqueue, cmap and csmap, all support reserve().
Note that on failure, the container will still be in a valid state, equal to before the reserve() call.