【问题标题】:Infinite loop(?) while trying to enqueue instance of user-defined class into queue尝试将用户定义类的实例排入队列时出现无限循环(?)
【发布时间】:2013-02-09 05:11:36
【问题描述】:

所以我有一个 Queue 类的双向链表实现(见下文) 当我尝试将整数和字符串排入队列时,此队列类工作得非常好,但由于某种原因,当我尝试将自定义类排入队列时,我的程序永远不会超过在 main 中调用 enqueue() 的行。我认为这可能是一个无限循环,但我不确定。简而言之,为什么我的 enqueue() 方法适用于 int、char 和字符串等基本数据类型,但不适用于自定义类?

这是我的队列类...

//
//  queue.h
//  
//
//  Created by Aaron Mamparo on 2/22/13.
//
//

#ifndef _queue_h
#define _queue_h

#include <iostream>
#include <stdio.h>

using namespace std;

template<class Type>
class Node {
public:
    Type elem;
    Node* next;
    Node* prev;
    Node() {}
    Type Elem() { return elem; }
    Node* Next() { return next; }
    Node* Prev() { return prev; }
};

template<class Type>
class Queue {
    Node<Type> *head;
    Node<Type> *tail;
public:
    Queue();
    ~Queue();
    bool isEmpty();
    int size();
    void enqueue(Type);
    Type dequeue();
    Node<Type>* at(int);
    Type get(int);
};

//default constructor
template<class Type>
Queue<Type>::Queue(){
    head = NULL;
    tail = NULL;
}

//destructor
template<class Type>
Queue<Type>::~Queue(){
    if(!isEmpty()){
        while(head){
            Node<Type> *del = head;
            head = head->next;
            delete[] del;
        }
    }
}

//return true if queue is empty
template<class Type>
bool Queue<Type>::isEmpty(){
    return head == NULL;
}

//return number of elems in queue
template<class Type>
int Queue<Type>::size(){
    int count = 0;
    Node<Type> *temp = head;
    while(temp){
        temp = temp->next;
        count++;
    }
    delete temp;
    return count;
}

//insert elem to back of queue
template<class Type>
void Queue<Type>::enqueue(Type T){
    Node<Type> *newNode = new Node<Type>();
    newNode->elem = T;
    newNode->next = NULL;
    if(head==NULL){
        head = tail = newNode;
        newNode->prev = NULL;
    } else {
        newNode->prev = tail;
        tail->next = newNode;
        tail = newNode;
    }
}

//remove elem from front of queue
template<class Type>
Type Queue<Type>::dequeue(){
    if(isEmpty()){
        cerr << "Error: trying to dequeue from empty queue" << endl;
    } else {
        Type ret = head->Elem();
        Node<Type> *del = head;
        head = head->next;
        delete del;
        return ret;
    }
}

//return a pointer to element at position i
template<class Type>
Node<Type>* Queue<Type>::at(int i){
    if(isEmpty()){
        return '\0';
    } else if (i>size()-1){
        return NULL;
    } else {
        Node<Type> *temp = new Node<Type>();
        temp = head;
        for(int j=0; j<i; j++){
            temp = temp->next;
        }
        return temp;
    }
}

//remove & return element at position i
template<class Type>
Type Queue<Type>::get(int i){
    if(isEmpty()){
        return NULL;
    } else if (i>size()-1){
        return NULL;
    } else {
        Node<Type> *temp = new Node<Type>();
        temp = head;
        for(int j=0; j<i; j++){
            temp = temp->next;
        }
        temp->prev->next = temp->next;
        temp->next->prev = temp->prev;
        Type ret = temp->Elem();
        delete temp;
        return ret;
    }
}
#endif

我的主驱动程序不会超过stateQueue.enqueue(state);

int main() {
    Queue<State> stateQueue;
    State newState = readInput();    //'readInput()' returns an instance of 'State'
    stateQueue.enqueue(newState);

    cout << "DONE" << endl;
    return 0;
}

在上面的代码中,“DONE”永远不会显示... 我确定readInput() 不是问题,因为当我在.enqueue() 调用之前插入它时会打印“DONE”... 有什么想法吗?

提前致谢

编辑:这是我的State 类的默认构造函数、复制构造函数、析构函数和重载赋值运算符...

State::State(){
    pieces = Queue<Piece>();
    stateHistory = Queue<string>();
    moveHistory = Queue<string>();
    rows = 0;
    cols = 0;
}

//copy constructor
State::State(const State& rhs){
    pieces = rhs.pieces;
    stateHistory = rhs.stateHistory;
    moveHistory = rhs.moveHistory;
    rows = rhs.rows;
    cols = rhs.cols;
}

//destructor
State::~State(){
}

//overloaded assignment operator
State& State::operator=(const State &rhs){
    pieces = rhs.pieces;
    stateHistory = rhs.stateHistory;
    moveHistory = rhs.moveHistory;
    rows = rhs.rows;
    cols = rhs.cols;
    return *this;
}

编辑:这是我刚刚实现的复制构造函数和重载赋值运算符...

template<class Type>
Queue<Type>::Queue(const Queue<Type>&Q)
{
    *this = Q;
}

template<class Type>
Queue<Type>& Queue<Type>::operator=(const Queue<Type> &Q)
{
    head = Q.head;
    tail = Q.tail;
    return *this;
}

【问题讨论】:

  • 你试过调试了吗?
  • 是的,我已经尝试过多次单步执行,但无法找出问题所在...我将设置一个断点并再次单步执行,这样我就可以准确地告诉您它停止的位置,给我一分钟..
  • 如果在您尝试使用自定义类之前它仍然有效,那么您的自定义类中可能存在缺陷。可能涉及默认构造或赋值。
  • 嗯...我在 queue.h 中的 enqueue() 处设置了一个断点,并在它处理 newState 时逐步执行它,它一直执行到方法的末尾很好...但是当我退出 main 时,告诉我程序所在行的调试器箭头消失了,我不知道为什么...
  • 好的,我刚刚从我的State 类中添加了一个sn-p 代码...但我仍然不知道是什么原因造成的...

标签: c++ linked-list queue doubly-linked-list


【解决方案1】:

简而言之,为什么我的 enqueue() 方法适用于 int、char 和字符串等基本数据类型,但不适用于自定义类?

很难确定,因为您没有提供 State 类的详细信息,但问题似乎存在,您有一个原始指针或其他东西,并且没有实现您在队列中使用的正确赋值运算符:: enqueue() 方法:

newNode->elem = T;

PS 您添加了 State 实现(虽然不是定义),但它表明它在内部使用 Queue 类本身。状态赋值使用的是编译器生成的Queue赋值运算符,但是Queue类有原始指针,所以你得到了头指针的双重删除。

一种可能的解决方案是将指向对象的指针存储在队列中,而不是对象本身:

typedef boost::shared_ptr<State> StatePtr;
int main() {
    Queue<StatePtr> stateQueue;
    StatePtr newState = readInput();    //'readInput()' now returns a smart pointer to 'State'
    stateQueue.enqueue(newState);

    cout << "DONE" << endl;
    return 0;
}

您需要相应地更改 readInput()。 另外我建议禁止复制和分配 Queue 对象,以便编译器帮助您防止此类问题。

【讨论】:

  • 啊,我明白你的意思了...但是我该如何解决这个问题?我很抱歉所有的问题......我是 c++ n00b
  • 为队列实现正确的复制构造函数和赋值运算符
  • 好的,我用我实现的复制构造函数和赋值运算符更新了原始帖子......但它仍然不起作用
  • 这不是正确的实现,这正是编译器之前生成的。另一种解决方案是不复制 State,而是将智能指针传递给它。
  • 我仍然不完全理解您提出的解决方案...我应该重新实现我的队列类来存储指针而不是节点吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-12
  • 2019-10-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多