简体   繁体   中英

C++ Memory Leak With STL Vector

I am building a templated Max Heap class in C++ for a datastructures class. The implementation demonstrates a Max Heap with a vector under the hood. There is an online submission associated with the assignment and when I submit mine, all the tests (push, pop, top, and size) pass and work (for the online unknown unit tests as well as all the ones I wrote) and I have no memory leaks with any of my tests, however I am failing the memory leak section with the online submission, indicating to me that my Bubble Up (Reheap Up) or Bubble Down (Reheap Down) algorithms are doing something funny with vector indices.

I noticed that I used the bracket operator a lot to mess with the vector, so I went through and changed all the brackets to .at() so I could see any suppressed out of bounds errors. Flying colors again, except for the memory leaks allegedly. I then figured well maybe one of the unit tests is adding sooo many values the vector fails to clear them all for some unknown reason...wasn't the case because I added so many values to a vector in my max heap class in my unit tests it took 90 seconds to finish and after all 52K allocations were made 52K deallocations were made as well and valgrind reported no errors.

Below is some of the main code for the class, if anyone could decide where some code is written that in some situation may warrant a memory leak that would be great!

template <class T> 
class MaxHeap {
public: 

MaxHeap(){ 
  // TODO: Fill me in
}

~MaxHeap() {
  data.clear();
}

void push(T value){
  data.push_back(value);
  bubbleUp(data.size()-1, value);
}

void pop(){
  if(!size()) {
    return;
  }
  T val = data.at(size()-1);
  data.pop_back();
  if(!size()) {
    return;
  }
  data.at(0) = val;
  bubbleDown(0, val);
}

T top(){
  if(!data.size()) throw logic_error("Empty Heap");
  return data.at(0);
}

unsigned int size(){
  return data.size();
}

void print_vec() {
  for (int i = 0; i < size(); ++i) {
    cout << data.at(i) << " ";
  }
  cout << endl;
}

vector<T> getVec() {
  return data;
}

private:
  vector<T> data;
  void bubbleUp(int idx, T value) {
    int position = idx;
    int parent_idx = parent(position);

    while (data.at(parent_idx) < value) {
      data.at(position) = data.at(parent_idx);
      data.at(parent_idx) = value;
      position = parent_idx;
      parent_idx = parent(position);
    }
  }

  void bubbleDown(int idx, T value) {
    int left_child_idx = left_child(idx);
    int right_child_idx = right_child(idx);
    int max_child_idx;

    if(left_child_idx <= size()-1) {  // left child (consequently right child) in bounds of vector
      if(left_child_idx == size()-1) { // no right child, left is maxchild
        max_child_idx = left_child_idx;
      } else {
        max_child_idx = (data.at(left_child_idx) <= data.at(right_child_idx)) ? right_child_idx : left_child_idx;
      }

      if(data.at(idx) < data.at(max_child_idx)) {
        data.at(idx) = data.at(max_child_idx);
        data.at(max_child_idx) = value;
        bubbleDown(max_child_idx, value);
      }
    }
  }

  int left_child(int idx) {return (idx*2+1);}
  int right_child(int idx) {return (idx*2+2);}
  int parent(int idx) {return ((idx-1)/2);}

};

Warning : this is only a theory, since it is improbable that the source of leak is in the code shown here.

If T is a malformed type, that does not release it's memory when using the assignment operator, then this might be the part that trigger this bad behvior:

T swap; // initialized to something. perhaps using new

while (data.at(parent_idx) < value) {
  swap = data.at(parent_idx); //assume no delete in T.operator=()
  data.at(parent_idx) = value;
  data.at(position) = swap;
  position = parent_idx;
  parent_idx = parent(position);
}

This is not a problem in this code . However, you might still be able to patch it here. Why is T defined outside the loop?

while (data.at(parent_idx) < value) {
  T swap = data.at(parent_idx); // no assignment here
  data.at(parent_idx) = value;
  data.at(position) = swap;
  position = parent_idx;
  parent_idx = parent(position);
}

===

Unrelated but better - don't use the unnecessary intermediate variable, and mix in move semantics:

while (data.at(parent_idx) < value) {
  data.at(position) = std::move(data.at(parent_idx));
  data.at(parent_idx) = value;
  position = parent_idx;
  parent_idx = parent(position);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM