3

I have tried to implement solution to dynamical expansion of array as user is entering new data in main as shown:

ComplexNumber** nizKompl = new ComplexNumber*[1];
bool unos = true;

while(unos){
  cout << "Unesite novi kompleksni broj(realni imaginarni): ";

  if(cin >> re >> im){ 
    nizKompl[brojUnesenih] = new ComplexNumber(re,im);
    ++brojUnesenih;

    ComplexNumber** nizTemp = new ComplexNumber*[brojUnesenih+1];
    copy(nizKompl, nizKompl+brojUnesenih, nizTemp);

    for(int i=0; i<brojUnesenih; ++i){
      delete nizKompl[i];
    }

    delete [] nizKompl;
    nizKompl = nizTemp; 
  } else {
    cout << endl << endl;
    unos = false;
  }
}

ComplexNumber is custom type. ComplexNumber works fine but I am having problem with double free or corruption error as I am entering new data and creating new ComplexNumbers in program.

Is there some better way to achieve this? I need to use my own dynamical array instead of std::vector because It is for educational purpose.

As I understand double free error occurs when you try to free memory which is already free'd. But It seems that I just can't resolve the issue, as I can see no double free should happen.

Is something happening in memory of which I have no knowledge? Is it problem with std::copy as I am copying array of pointers of pointers?

I would really appreciate any help or suggestion. Thank you!

  • 12
    Use `std::vector`, and avoid such problems. – Jarod42 Mar 21 '18 at 15:56
  • http://en.cppreference.com/w/cpp/container/vector – Raxvan Mar 21 '18 at 15:56
  • Life always goes better with std::vector – pm100 Mar 21 '18 at 15:57
  • Possible duplicate of [How to create a dynamic array of integers](https://stackoverflow.com/questions/4029870/how-to-create-a-dynamic-array-of-integers) – Raedwald Mar 21 '18 at 15:58
  • 1
    Your problem is the loop `for(int i=0; i – WhozCraig Mar 21 '18 at 16:07
  • Wow so many std::vector! Well thank you all but I need to implement my own dynamical array as I am studying c++ and trying to understand how pointers work! @WhozCraig Thanks for answering my question! – Adnan Selimovic Mar 21 '18 at 16:14
  • 1
    @AdnanSelimovic *I need to implement my own dynamical array* -- Then implement a generic dynamic array *class*, where at the very least you actually learn something worth your time. Things like the rule of 3, proper cleanup, overloading assignment and copy constructor, etc.. You learn very little with having `new[]` and `delete[]` strewn all over the code. – PaulMcKenzie Mar 21 '18 at 16:22

4 Answers4

6

If you really need not to use std::vector (for educational reasons), then your problem is here:

for(int i=0; i<brojUnesenih; ++i){
  delete nizKompl[i];
}

you just copied those pointers to your new, slightly bigger array. If you delete the objects they point to, your new array is full of unusable dangling pointers.

The proximate fixes are:

  1. just don't delete these objects. Consider ownership transferred to the new array and keep them alive. Delete the three lines quoted above.
  2. OR if you really want to delete the originals, you need to copy them first - this means a deep copy of the object rather than a shallow copy of the pointer, so your new array should be populated like

    // shallow copy:
    // copy(nizKompl, nizKompl+brojUnesenih, nizTemp);
    // deep copy:
    transform(nizKompl, nizKompl+brojUnesenih, nizTemp, clone);
    

    with the function

    ComplexNumber* clone(ComplexNumber *original) {
      return new ComplexNumber(*original);
    }
    

    NB. I can't think of any good reason to do this, it's just wasteful.

Useless
  • 55,472
  • 5
  • 73
  • 117
3

Use std::vector<ComplexNumber> and use push_back to allocate memory dynamically.

Your code will look something like this:

std::vector<ComplexNumber> nizKompl;

while(true) {
  cout << "Unesite novi kompleksni broj(realni imaginarni): ";

  if(cin >> re >> im){
    nizKompl.push_back({re,im});
  } else {
    cout << endl << endl;
    break;
  }
}
schorsch312
  • 5,032
  • 4
  • 21
  • 47
  • I am aware of existence of std::vector but as I have stated in my question I need to use dynamical array. – Adnan Selimovic Mar 21 '18 at 16:04
  • Quote form `cppreference.com` " std::vector is a sequence container that encapsulates dynamic size arrays.". `std::vector` is the dynamic array of the standard template library. – schorsch312 Mar 21 '18 at 16:06
  • Sorry I haven't been clear but I need to implement my own dynamical array. – Adnan Selimovic Mar 21 '18 at 16:09
  • Why? Unless you have a very good reason to do so, don't do it. You will have a very hard time doing a better job the the maintainers of the stl already did. – schorsch312 Mar 21 '18 at 16:13
  • @schorsch312 Judging by the verbiage from the OP, his very good reason is assignment requirements and a grade ultimately depends on it. I completely concur in the real world common sense says use a vector; who ever said academia was anything like the real world. – WhozCraig Mar 21 '18 at 16:18
2

As already mentioned, using std::vector would be the right approach.

But wrt your exact question:

for(int i=0; i<brojUnesenih; ++i){
    delete nizKompl[i];
}

This is what causes the double delete, since you copy the same pointers to your new array and also delete them. When entering the first number, you'll create an array of size one and create an object. On the second number, you'll allocate a new array of size two, copy the first element over to the new array, but also delete it. And once you add the third element, you'll create a new array of size three, copy the first two pointers and again try to delete them, but the first pointer was already deleted.

nVxx
  • 601
  • 7
  • 18
1

It is unclear why you are not using the standard class std::vector and using pointers instead of objects themselves.

Nevertheless it seems you mean something like the following

#include <iostream>
#include <algorithm>
#include <memory>

struct ComplexNumber
{
    ComplexNumber() : ComplexNumber( 0, 0 ) {}
    ComplexNumber( int re, int im ) : re( re ), im( im ) {}
    int re;
    int im;
};

int main() 
{
    ComplexNumber **nizKompl = nullptr;
    size_t brojUnesenih = 0;
    bool unos;

    do
    {
        std::cout << "Unesite novi kompleksni broj(realni imaginarni): ";

        int re, im;

        if( ( unos = !!( std::cin >> re >> im ) ) )
        { 
            ComplexNumber **nizTemp = new ComplexNumber * [brojUnesenih + 1];

            std::copy( nizKompl, nizKompl + brojUnesenih, nizTemp );
            nizTemp[brojUnesenih] = new ComplexNumber( re, im );

            ++brojUnesenih;

            delete [] nizKompl;
            nizKompl = nizTemp;
        }
    } while ( unos );

    for ( size_t i = 0; i < brojUnesenih; i++ )
    {
        std::cout << "{ " << nizKompl[i]->re 
                  << ", " << nizKompl[i]->im
                  << " } ";
    }
    std::cout << std::endl;

    if ( nizKompl )
    {
        std::for_each( nizKompl, nizKompl + brojUnesenih, std::default_delete<ComplexNumber>() );
    }

    delete [] nizKompl;

    return 0;
}   

The program output might look like

Unesite novi kompleksni broj(realni imaginarni): 1 1
Unesite novi kompleksni broj(realni imaginarni): 2 2
Unesite novi kompleksni broj(realni imaginarni): 3 3
Unesite novi kompleksni broj(realni imaginarni): 4 4
Unesite novi kompleksni broj(realni imaginarni): 5 5
Unesite novi kompleksni broj(realni imaginarni): a
{ 1, 1 } { 2, 2 } { 3, 3 } { 4, 4 } { 5, 5 } 
Vlad from Moscow
  • 224,104
  • 15
  • 141
  • 268