0

I'm trying to implement a dynamic template queue in c++, but when I call the destructor I get a "double free or corruption (out)" error. Unfortunately I'm not allowed to change the file structure, or add any new methods/classes, or change the class/method declerations. I tried adding 5 items to a queue(rq1), before printing it out and destructing it, the print works fine, but I get an error when I destruct. Here is my code:

main.cpp

#include "resrcQueue.h"
#include <string>
#include <iostream>

using namespace std;

int main(){
  queueNode<string>* q1 = new queueNode<string>("apples",100);
  queueNode<string>* q2 = new queueNode<string>("lemons",200);
  queueNode<string>* q3 = new queueNode<string>("gold",10);
  queueNode<string>* q4 = new queueNode<string>("stone",11);
  queueNode<string>* q5 = new queueNode<string>("brick",12);

  resrcQueue<string> rq1;
  rq1.enqueue(q1);
  rq1.enqueue(q2);
  rq1.enqueue(q3);
  rq1.enqueue(q4);
  rq1.enqueue(q5);
  rq1.print();

  delete &rq1;

  return 0;
}

rsrcQueue.h

#ifndef RQUEUE
#define RQUEUE

#include <string>
#include <iostream>
#include "queueNode.h"

using namespace std;

template <class T>
class resrcQueue{
private:
  queueNode<T>* head;
  queueNode<T>* tail;

public:
  resrcQueue();
  ~resrcQueue();
  void enqueue(queueNode<T>* t);
  void dequeue();
  queueNode<T>* peek();
  void print();
  int tallyWeight();
  string calculateStorageRequirements();
};

#include "resrcQueue.cpp"

#endif

resrcQueue.cpp

#include "resrcQueue.h"
#include <string>
#include <iostream>

using namespace std;

template <class T>
resrcQueue<T>::resrcQueue(){
  head=NULL; tail=NULL;
}

template <class T>
resrcQueue<T>::~resrcQueue(){
  queueNode<T>* currNode=head;
  queueNode<T>*temp;
  int count=1;
  while(head){
    cout<<count<<endl;
    this->dequeue();
    count++;
  }
}

template <class T>
void resrcQueue<T>::enqueue(queueNode<T>* t){
  queueNode<T>*newNode=NULL;
  newNode = new queueNode<T>(t->getResrc(),t->getWeight());
  if(head){//not empty
    tail->next=newNode;
    tail=newNode;
  }else{//empty
    head=newNode;
    tail=newNode;
  }
}

template <class T>
void resrcQueue<T>::dequeue(){
  if(head){//not empty
    queueNode<T>* temp=head;
    head=head->next;
    delete temp;
  }else{//empty
    cout<<"EMPTY"<<endl;
  }
}

template <class T>
queueNode<T>* resrcQueue<T>::peek(){
  return head;
}

template <class T>
void resrcQueue<T>::print(){
  queueNode<T>* currNode=head;
  while(currNode){
    cout<<"Resource: "<<currNode->getResrc()<<endl;
    cout<<"Quantity: "<<currNode->getWeight()<<endl;
    currNode=currNode->next;
  }
}

template <class T>
int resrcQueue<T>::tallyWeight(){
  int totalWeight=-1;

  if(head){
    totalWeight=0;
    queueNode<T>* currNode=head;
    while(currNode){
      totalWeight+=currNode->getWeight();
      currNode=currNode->next;
    }
  }

  return totalWeight;

}

template <class T>
string resrcQueue<T>::calculateStorageRequirements(){
  int numNodes=0;
  queueNode<T>* currNode=head;
  while(currNode){
    numNodes++;
    currNode=currNode->next;
  }

  string r;

  if(this->tallyWeight()<100){
    r="wooden crate";
  }else if(this->tallyWeight()>200 && numNodes>5){
    r="steel crate";
  }else if(numNodes>5){
    r="silo";
  }else{
    r="LOGISTICS ERROR";
  }

  return r;
}

queueNode.h

#ifndef QNODE
#define QNODE

#include <string>
#include <iostream>

using namespace std;

template <class T>
class queueNode{
private:
  T resrc;
  int weight;
public:
  queueNode* next;
  queueNode(T r, int w);
  ~queueNode();
  T getResrc();
  int getWeight();
};

#include "queueNode.cpp"

#endif

queueNode.cpp

#include <string>
#include <iostream>
#include "queueNode.h"

using namespace std;

template <class T>
queueNode<T>::queueNode(T r, int w){
  next=NULL;
  resrc=r; weight=w;
  //cout<<"Init with weight: "<<weight<<", and resource: "<<resrc<<endl;
}

template <class T>
queueNode<T>::~queueNode(){
  cout<<"Resource Unit Destroyed"<<endl;
}

template <class T>
T queueNode<T>::getResrc(){
  return resrc;
}

template <class T>
int queueNode<T>::getWeight(){
  return weight;
}

makefile

main.out: main.cpp queueNode.h queueNode.cpp
    g++ -static -g main.cpp -o main.out
run: main.out
    ./main.out
clean: main.out
    rm main.out

Apologies if the question is a little specific and if I included too much code, I couldn't manage to duplicate the error which is why I posted the original code where I got the error, and I did struggle quite a lot of hours to fix it myself before posting it here, I will decrease the code length if it'll be better that way.

Foxly
  • 1
  • 1
  • Only `delete` what you actually `new`! If you don't create an object with `new` you should never attempt to `delete` it. – Some programmer dude Oct 19 '19 at 02:14
  • partial answer: [Calling delete on variable allocated on the stack](https://stackoverflow.com/questions/441831/calling-delete-on-variable-allocated-on-the-stack) – walnut Oct 19 '19 at 02:14
  • This is still way too much code. Cut it down to just the bare minimum that exhibits the same behaviour, and don't split it between multiple source files unless that's actually relevant somehow. – Ayjay Oct 19 '19 at 02:16
  • Possible duplicate of [Calling delete on variable allocated on the stack](https://stackoverflow.com/questions/441831/calling-delete-on-variable-allocated-on-the-stack) – JaMiT Oct 19 '19 at 02:21
  • @Ayjay Okay, I will cut it down, I'm new here so I welcome the criticism. – Foxly Oct 19 '19 at 02:21
  • @Someprogrammerdude Okay thanks a lot! After fixing that I still get a segmentation fault (core dumped) error. – Foxly Oct 19 '19 at 02:25
  • Please don't chain multiple problems onto a single question like that. For new problems please post new questions. And besides refresh about how to create a [mcve], also please reread [how to ask good questions](http://stackoverflow.com/help/how-to-ask), as well as [this question checklist](https://codeblog.jonskeet.uk/2012/11/24/stack-overflow-question-checklist/). – Some programmer dude Oct 19 '19 at 02:31

1 Answers1

3

There's a reason we ask people to make a MCVE - in the process of doing this you'll probably find the answer to your question.

When you take your program and strip out ALL of the unnecessary code and consolidate it into one file that still exhibits the bug, you get something like this:

#include <string>
using namespace std;

template <class T>
class resrcQueue{ };

int main(){
  resrcQueue<string> rq1;

  delete &rq1;
}

This still exhibits the bug. The reason for this is you can't delete stack variables. Remove the delete statement.

#include <string>
using namespace std;

template <class T>
class resrcQueue{ };

int main(){
  resrcQueue<string> rq1;
}
Ayjay
  • 3,413
  • 15
  • 20
  • Okay thanks! I'll be sure to put more time into getting my MCVE working from now on. I don't understand what you mean you can't delete stack variables? Isn't it just a class I define? And I also don't understand how this answers my question of the destructor not working, since the example I'm given requires a destructor we don't have an option to just remove it as far as I know :) – Foxly Oct 19 '19 at 02:33
  • The type doesn't matter - all types can be allocated on the heap or on the stack. What matters is how you define it. `int i = 0;` is a stack variable. It is allocated on the stack, and it will be deallocated (and have its destructor called) when it goes out of scope. `int* i = new int {};` is a heap variable. It is allocated on the heap, and will only have the destructor called and be deallocated when you call `delete i;`. – Ayjay Oct 19 '19 at 03:20
  • @Foxly In this case, since rq1 is a stack variable, the destructor will be called when it goes out of scope - in this case, it goes out of scope at the end of the `main()` function. [Observe](https://wandbox.org/permlink/COGys4z9Rsxm6ViB) – Ayjay Oct 19 '19 at 03:25