【问题标题】:C++ dynamic template queue "double free or corruption (out)" after calling destructor调用析构函数后 C++ 动态模板队列“双重释放或损坏(出)”
【发布时间】:2020-02-15 23:43:34
【问题描述】:

我试图在 C++ 中实现一个动态模板队列,但是当我调用析构函数时,我得到一个“双重释放或损坏(out)”错误。不幸的是,我不允许更改文件结构,或添加任何新方法/类,或更改类/方法声明。我尝试将 5 个项目添加到队列(rq1),在打印出来并销毁它之前,打印工作正常,但是当我销毁时出现错误。这是我的代码:

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;
}

制作文件

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

抱歉,如果问题有点具体,并且如果我包含太多代码,我无法复制错误,这就是为什么我在出现错误的地方发布了原始代码,我确实遇到了很多困难在这里发布之前要自己修复几个小时,如果这样会更好,我会减少代码长度。

【问题讨论】:

  • 只有delete 你实际上是new!如果您不使用 new 创建对象,则永远不要尝试使用 delete 它。
  • 这仍然是太多的代码。将其减少到表现出相同行为的最低限度,并且不要将其拆分为多个源文件,除非这实际上以某种方式相关。
  • @Ayjay 好的,我会减少它,我是新来的,所以我欢迎批评。

标签: c++ templates dynamic queue


【解决方案1】:

我们要求人们创建MCVE 是有原因的 - 在此过程中,您可能会找到问题的答案。

当你把你的程序去掉所有不必要的代码并将它合并到一个仍然存在错误的文件中时,你会得到这样的结果:

#include <string>
using namespace std;

template <class T>
class resrcQueue{ };

int main(){
  resrcQueue<string> rq1;

  delete &rq1;
}

这仍然存在错误。原因是您不能删除堆栈变量。删除删除语句。

#include <string>
using namespace std;

template <class T>
class resrcQueue{ };

int main(){
  resrcQueue<string> rq1;
}

【讨论】:

  • 好的,谢谢!从现在开始,我一定会花更多时间让我的 MCVE 正常工作。我不明白你的意思是你不能删除堆栈变量?不就是我定义的一个类吗?而且我也不明白这如何回答我关于析构函数不起作用的问题,因为我给出的示例需要一个析构函数,据我所知,我们没有选择将其删除:)
  • 类型无关紧要——所有类型都可以分配在堆上或栈上。重要的是你如何定义它。 int i = 0; 是一个堆栈变量。它在堆栈上分配,并且在超出范围时将被释放(并调用其析构函数)。 int* i = new int {}; 是一个堆变量。它是在堆上分配的,只有当你调用delete i;时才会调用析构函数并被释放。
  • @Foxly 在这种情况下,由于 rq1 是一个堆栈变量,所以当它超出范围时将调用析构函数 - 在这种情况下,它在 main() 的末尾超出范围功能。 Observe
猜你喜欢
  • 2014-06-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多