从空队列中删除元素
Deleting an element from an empty queue?
我正在编写抽象数据类型的优先级队列,作为大学的任务,其他人将使用它。我的类dequeue中有一个函数,它删除队列中的第一个元素并返回该元素的数据。但是,当我试图从一个空队列中删除一个元素时,程序会崩溃。我在这里该怎么办?
如果有帮助的话,下面是代码:
#ifndef PRIORITYQUEUE_H
#define PRIORITYQUEUE_H
#include <iostream>
using namespace std;
const int max_queue_items = 1000;
template<class T>
struct node{
T data;
int priority;
node *next;
};
template<class T>
class PriorityQueue
{
public:
/*
Constructor that creates an empty queue.
*/
PriorityQueue(){
head = NULL;
size = 0;
}
/*
Adds an element to the queue.
Params:
data - data of the element
priority - priority of the element
*/
bool is_empty(){
if (size == 0){
return true;
}
return false;
}
bool is_full(){
if (size == max_queue_items){
return true;
}
return false;
}
/*
Adds an element to thq queue.
It gets inserted before the first element with
lower priority.
*/
void enqueue(T data, int priority){
node<T> * previous = NULL;
node<T> * now = head;
while (now != NULL && now->priority >= priority){
previous = now;
now = now->next;
}
node<T> * new_element = new node<T>;
new_element->data = data;
new_element->priority = priority;
new_element->next = now;
if (previous == NULL){
head = new_element;
} else {
previous->next = new_element;
}
size++;
}
/*
Removes the first element in the queue
*/
T dequeue(){
T data;
if (!is_empty()){
node<T> * now = head;
data = now->data;
head = head->next;
delete now;
size--;
}
return data;
}
/*
Returns the priority of the first element.
It's always the highest priority in the queue.
*/
int get_first_priority(){
return head->priority;
}
/*
Returns the data of the first element in the queue.
*/
T get_first_value(){
if (is_empty())
throw 0;
return head->data;
}
/*
Returns the number of elements in the queue.
*/
int get_size(){
return size;
}
/*
Deletes the whole queue from the memory.
*/
void flush(){
node<T> * now;
while (head != NULL){
now = head;
head = head->next;
delete now;
size--;
}
}
/*
Prints the whole queue following this format:
data(priority)
*/
void print(){
node<T> * now = head;
while (now != NULL){
cout << now->data << "(" << now->priority << ")" << endl;
now = now->next;
}
}
private:
node<T> * head; // Pointer to the head of the queue
int size; // Number of elements in the queue
};
#endif // PRIORITYQUEUE_H
这可能是问题的根源,也可能不是,但我肯定会认为这是一个问题。在函数dequeue()
中,当is_empty()
返回true
:时,您可能会返回一个未初始化的变量(如果T
不是类类型)
T dequeue()
{
T data; // Uninitialized if T is not a class type
if (!is_empty())
{
node<T> * now = head;
//--------------------------------------------------------------
// This initialization is skipped when `is_empty()` returns true
data = now->data;
//--------------------------------------------------------------
head = head->next;
delete now;
size--;
}
return data;
}
根据您对该函数返回的值所做的操作以及T
的类型,您的程序可能具有Undefined Behavior(我可以想象T
是您稍后取消引用的指针类型)。
您可能想将函数的第一行更改为:
T data = T();
它强制执行data
对象的值初始化。如果T
是类类型,则将调用默认构造函数。否则,data
将被零初始化。
调用dequeue()
的函数在使用返回值之前应该检查它(或者更好的方法是,在尝试从中弹出值之前,在队列上调用is_empty()
以检查它是否为空)。
当调用dequeue()
并且队列为空时,您甚至可以考虑抛出异常:
T dequeue()
{
if (is_empty())
{
// Requires including the <stdexcept> standard header
throw std::logic_error("Queue is empty");
}
node<T> * now = head;
T data = now->data;
head = head->next;
delete now;
size--;
return data;
}
客户端现在负责确保dequeue()
永远不会在空队列上被调用(或者他们将把对dequeue()
的调用封装到try/catch
块中,以处理可能引发的异常
另一种可能性是向客户端返回一个bool
,指示该值是否成功弹出,可能会将弹出的元素分配给通过引用传递的参数:
bool dequeue(T& data)
{
if (is_empty())
{
return false;
}
node<T> * now = head;
data = now->data;
head = head->next;
delete now;
size--;
return true;
}
通过这种方式,客户端负责检查函数的结果。如果函数返回false
,data
变量将被初始化为客户端将其初始化为的任何值。处理错误情况的责任再次转移到客户端。
我认为存在一些问题。
首先也是最重要的一点是,类没有析构函数。如果不是所有元素都在程序中出列,那么就会出现内存泄漏。编写析构函数或使用智能指针而不是原始指针。
其次,正如@Andy Prowl(顺便说一句,谁知道如何在推特这样的帖子中@人们?)所说,应该考虑未初始化的局部变量。T data = T()
对于内置类型和自定义类型都能很好地工作。
第三,我认为队列有容量限制max_queue_items
,但入队部分没有相应的代码。
尽管如此,我不认为所有这些缺陷在正常情况下都会导致严重的崩溃。也许问题发生在您的代码调用类中,对未初始化的返回值的错误处理会导致崩溃。
我在您的出队列中看到的唯一潜在问题是您正在创建未知类型T的临时变量。如果您在优先级队列中存储没有默认构造函数的类型的数据,那么当您的出队调用并尝试默认构造该变量时,您将遇到问题。
如果是这种情况,我建议您重新处理优先级队列,以保存指向模板类型的指针,而不是数据本身。
- 如何从存储在std::映射中的std::集中删除元素
- 从嵌套在std::映射中的std::列表中删除元素的最佳方式
- 从矢量中删除元素后出现隔离错误
- 如何使用remove_if从矢量中删除元素
- 如何从使用 for 循环中的矢量大小的矢量中删除元素
- C++映射不删除元素
- 如何从标准::元组中删除元素?
- 在动态数组中添加/删除C++元素
- 如何通过比较彼此的成员从QStringList中删除元素
- 如何修复从矢量中删除元素的错误?
- 从 std::set 中删除元素,同时在 C++17 中迭代该元素
- 使用remove_if从矢量中删除元素
- 用C++从三维矢量中删除元素
- 从对象数组中删除元素
- 如何在不使用 vector::erase() 的情况下编写自定义 Vector 方法来删除元素?
- C++ - 按自定义数据类型向量的值删除元素
- 从任意容器中廉价删除元素的惯用方法?
- 从数组中删除元素不起作用的函数
- 删除元素 BST
- 从向量中删除元素时未处理的异常