c++arraysdynamic-arraysdynamic-allocation

C++: Heap error when dynamically allocating array through nested class?


I'm trying to allocate memory for Uint8 type array through a nested class. When I'm doing so I think it runs to heap error and prompts the window that says Debug Assertion Error. Expression: _BLOCK_TYPE_IS_VALID(pHead->nBlockUse). My code is the following:

#include <iostream>
#include "dcmtk/dcmdata/dctk.h"
using namespace std;

class test
{
public:
    int a;
    Uint8 * b;
    test()
    {}
    test(int c)
    {
        a=c;
        b = new Uint8[a];
    }
    ~test()
    {
        delete [] b;
    }
};

class subTest
{
public:
    test h;
    subTest()
    {}
    subTest(test g)
    {
        h=g;
    }
    ~subTest()
    {
    }
};

int main()
{
    subTest f(test(5));
    for(int i=0; i<5; i++)
    {
        f.h.b[i] = Uint8((i*2)+1);
        cout<< int(f.h.b[i])<<endl;
    }

    return 0;
}

Could you find what mistake I'm doing?

Thanks.


Solution

  • As already mentioned in the comments and by others, the problem occurs because you did not follow the rule of three, that is, since you had to define a custom destructor(to delete the dynamically allocated memory), you should at least define a custom copy constructor(which does a deep copy of the array, that is, it allocates new memory and copies the content of the old array) and a custom copy assignment operator(that does essentially the same, so you could implement one in terms of the other).

    Example code for a copy constructor(suboptimal, of course):

    test(const test &other)
    {
      a=other.a
      b=new Uint8[a];
      for(size_t i=0;i<a;++i)
        b[i]=other.b[i];
    }
    

    As can be seen, this would involve a little work and is quite tedious, which is why you should prefarably follow the rule of zero and use classes that already deal with ownership issues intrinsically(which in your case should propably be a std::vector), so instead of dealing with your dynamically allocated array directly, change it to something akin to this:

    class test
    {
      public:
      std::vector<Uint8> b;
    
      test(int size)
      {
        b.resize(size);
      }
    }
    

    And all your problems vanish, because std::vector deals with the required deep copy itself, without your class having to worry about it.

    I hope this helps ;-)