0

I got a weird message everytime the destructor is called. Since one of my private variable is dynamic allocated array (int *member;), I write the destructor like this:

ClassSet::~ClassSet(){delete []member;}

Everytime the destructor for ClassSet is called, I got an error message:

Windows has triggered a breakpoint in Hw1.exe.

This may be due to a corruption of the heap, which indicates a bug in Hw1.exe or any of the DLLs it has loaded.

This may also be due to the user pressing F12 while Hw1.exe has focus.

entire class:

class ClassSet
{
  public:
    ClassSet(int n = DEFAULT_MAX_ITEMS);
ClassSet(const ClassSet& other);
ClassSet &operator=(const ClassSet& other);
~ClassSet();
  private:
    int size;
int *member;
 };

ClassSet::ClassSet(int n){
   size = n;
   member = new int[n];
}

ClassSet::ClassSet(const ClassSet& other){
    int i = 0;
    this->size = other.size;
member = new int [capacity];
while (i<size)
{
    this->member[i] = other.member[i];
    i++;
}
 }

 Multiset& Multiset::operator=(const Multiset &other)
 {
    if (&other == this){return *this;}
this->size = other.size;
int i = 0;
    delete [] member;
    member = new int[size];
while (i<other.size)
{
    this->member[i] = other.member[i];
    i++;
}
return *this;
}

Any idea what's wrong with this destructor?

Community
  • 1
  • 1
user1988385
  • 2,819
  • 4
  • 18
  • 17

4 Answers4

4

You failed to implement (or you have implemented incorrectly) one of ClassSet::ClassSet(const ClassSet&) or ClassSet::operator=(const ClassSet&).

In other words, you have violated the Rule of Three.

The best solution, however, is likely not to implement them, but rather to change how you allocate space for your dynamic array. Instead of using new[] and delete[], try replacing that member with a std::vector<>.

Robᵩ
  • 163,533
  • 20
  • 239
  • 308
  • I think I implement the copy constructor and operator= correctly. because when I assign "ClassSet aaa = b or ClassSet aaa; aaa=b" when I change an element in aaa, it does not change any element in b. – user1988385 Jan 21 '13 at 21:05
  • If you have implemented those correctly, then my theory is wrong. Regardless, I recommend that you do not use `new[]` directly, but use `std::vector` instead. – Robᵩ Jan 21 '13 at 21:18
3

Heap corruption is often something detected after-the-fact. It may have to do with your destructor, or as I've seen, can likely happen well before the heap access the error occurs at.

Basically "Heap corruption detected" simply means that on a given access of the heap, Windows decided that the current state of the heap was inconsistent/invalid. Something went bad a while earlier.

These bugs can be really hard to track down. One common cause of heap corruption though is double deletion you deleted something twice inadvertently. This can point at deeper issues with how your data is copied around your code and your design.

This can happen, as others have said, when you don't have an appropriate copy constructor/assignment operator that copies dynamic memory. The "copy" deletes your memory, then the initial class deletes again, causing a double delete.

Doug T.
  • 64,223
  • 27
  • 138
  • 202
1

If you've posted you actual code, then I think the problem is here:

ClassSet::ClassSet(const ClassSet& other){
    int i = 0;
    this->size = other.size;
    member = new int [capacity];  // <--- what is capacity?
    while (i<size)
    {
        this->member[i] = other.member[i];
        i++;
    }
}

You're sizing the copied array based on something named capacity which doesn't have any obvious relationship to other.size. If capacity is smaller than size the loop that copies elements will corrupt the heap.

Assuming that this is an academic exercise, once you solve this problem you should look into the copy/swap idiom that used for classes like these to ensure exception safety.

If this isn't an academic exercise, then you should be looking at std::vector or other containers that are provided in libraries.

Community
  • 1
  • 1
Michael Burr
  • 333,147
  • 50
  • 533
  • 760
  • capacity is a global constant (the number of element that the array member can have). size it the number element in the array that have been filled by user (not some random number that fill the array when the array is initiated) – user1988385 Jan 21 '13 at 22:39
0

This problem is quite common. The default copy constructor is equivalent to

ClassSet(const ClassSet& other) {
    size = other.size;
    member = other.member;
}

The problem with this is that when an instance ClassSet is copied, both the original instance and the new instance hold a raw pointer to member. Both destructors will free member, causing the double free problem you are seeing.

For example,

{
    ClassSet a
    ClassSet b(a); // assert(b.member == a.member)
} // At this point, both a and b will free the same pointer.

You can mitigate this by not allowing copying, or moving the pointer instead of copying.

Alex Chamberlain
  • 4,147
  • 2
  • 22
  • 49
  • am not using the default copy constructor and default operator = I think I implement the copy constructor and operator= correctly. because when I assign "ClassSet aaa = b or ClassSet aaa; aaa=b" when I change an element in aaa, it does not change any element in b. – user1988385 Jan 21 '13 at 22:06
  • @user1988385 Post it and we can check. – Alex Chamberlain Jan 21 '13 at 22:07