0

I would like to ask you how to reallocate a struct array in C++?

In C there is realloc which is quite good, but it is not recommended to use it in C++. Maybe some of you would tell me that I should not use a struct array?

Well, in this task we cannot use any STL containers, so struct is the only option, I suppose. It is for the matter of practice with allocation, reallocation of memory and other things...

In the example bellow I wrote a code how I would do it in C by using malloc and realloc. Can you give me an advice how to do it in C++.

Thanks.

class CCompany
{
  public:
      CCompany();
      bool NewAccount(const char * accountID, int initialBalance);
      struct ACCOUNT
      {
        char *accID;
        int initialBalance;
        ...
      };      
      ACCOUNT* accounts ;
      ...
      ...     
  private:      
      int ReallocationStep = 100;
      int accountCounter = 1;
      int allocatedAccounts = 100;
      ...
}

CCompany::CCompany()
{
    accounts = (ACCOUNT*)malloc(allocatedItems*sizeof(*accounts));
}


bool CCompany::NewAccount(const char * accountID, int initialBalance)
{
    // Firstly I check if there is already an account in the array of struct. If so, return false.
    ...
    // Account is not there, lets check if there is enough memory allocated.
    if (accountCounter == allocatedAccounts) 
    {
         allocatedAccounts += ReallocationStep;
         accounts = (ACCOUNT *) realloc(accounts, allocatedAccounts * sizeof(*accounts));
    }

   // Everything is okay, we can add it to the struct array
   ACCOUNT account = makeStruct(accID, initialBalance);
   accounts[CounterAccounts] = account;

   return true;
}
Paul Rooney
  • 20,879
  • 9
  • 40
  • 61
  • if you don't want to use `realloc`, you should also reconsider using `malloc`, when `new` is available. You should just do `new` for the larger size, copy across what you already have and then `delete[]`. Also be very wary that your `CCompany` class is taking in pointers to strings and storing them as non-owned (i.e. doesnt take a copy). – Paul Rooney Apr 06 '17 at 07:01
  • Yes, sure, instead of malloc I would use new, but I am not sure with realloc. – TheDoctor Bombastic Apr 06 '17 at 07:26
  • If there were a realloc equivalent in c++ using it would kill exception safety dead in its tracks. You want the old data still around after you allocate the new memory. The allocation can throw and would leave your code in an inconsistent state. You should allocate the new block and once you know that's succeeded then copy into the new block then delete the old one. – Paul Rooney Apr 06 '17 at 07:33

4 Answers4

0

If You have no possibility to use STL containers, maybe You should consider using some sort of list instead of array. Basing on Your code, this could be better solution than reallocating memory over and over the time.

WarNaX
  • 83
  • 7
  • We cannot use list or vector, otherwise I would – TheDoctor Bombastic Apr 06 '17 at 07:26
  • @TheDoctorBombastic, I am not talking about STL list. You can write Your own and add neccesary functions to iterate over it, add, count and delete elements. – WarNaX Apr 06 '17 at 08:10
  • Sure sure :-) I can alco develop a new system :and become the richest man in the world -) Anyway, I am learning it. I am in the first year of my studies and I am not able to do something like creating my own list :-) I have been programming in C++ for 1,5 month...:) – TheDoctor Bombastic Apr 06 '17 at 08:41
0

Personally I don't think that realloc is not recommended in C++, yet for many uses of malloc, realloc, free there are other concepts in C++ (like new, placement new, delete, ...), shifting the semantics more on "objects" rather than on "plain memory".

So it is still valid to use the realloc-approach as you did; And - if dynamic data structures like linked lists are not a choice - actually the realloc-metaphor is the best I can think of, because it avoids unnecessarily copying, deleting, recreating items again and again while still providing a continuous block of memory holding all the objects.

Stephan Lechner
  • 34,891
  • 4
  • 35
  • 58
0

According to other questions+answers(1, 2), you should avoid using malloc and realloc in C++ where possible.

The latter of those two references gives a good suggestion: If you're not allowed to use std::vector due to it being an STL container, perhaps std::fstream might be worth looking into as an alternative. This would suggest that working with files without relying upon excess working memory could be the intended goal of the assessment task. I can't see the assignment criteria, so I can't say whether or not this would be compliant.

Even with an assignment criteria on your side, some lecturers like to change requirements with little or no notice; in fact, sometimes just seeing a solution to the assignment that isn't what they had in mind will (unfairly) prompt such a modification. Any assessment that prompts you to reinvent std::vector seems silly to me, but if you have two options, and only one of them involves staying in your degree, I think your only solution will be to use realloc; there's no need for malloc here.

To reduce the overhead of calling realloc so often (as pointed out by another answer), you could remove two of your three counters, call realloc when the remaining counter is about to become a power of two, and reallocate by a factor of two like I did in push_back:

void *push_back(void **base, void const *value, size_t *nelem, size_t size) {
    typedef unsigned char array[size];
    array *b = *base;
    if (SIZE_MAX / sizeof *b <= *nelem) {
        return NULL;
    }

    if (*nelem & -~*nelem ? 0 : 1) {
        b = realloc(b, (*nelem * 2 + 1) * sizeof *b);
        if (!b) {
            return NULL;
        }
        *base = b;
    }

    b += (*nelem)++;
    return value
         ? memmove(b, value, sizeof *b)
         : b;
}
Community
  • 1
  • 1
autistic
  • 1
  • 3
  • 35
  • 80
0

The correct C++ way would be to use a std::vector which can deal nicely with reallocations. As your assignment do not allow you to use standard containers, you can:

  • either build a custom container using new and delete for reallocation and based on an array or a linked list
  • or directly use an array and stick to new and delete for reallocations - still acceptable C++
  • or revert to the good old malloc and realloc from the C standard library which is included in the C++ standard library. But you must be aware that this will not initialize the structs.

Because malloc/realloc would not call constructors, the last way must be seen as a low level optimization and the no initialization should be explicetely documented.

Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252