使用已实现的 LinkedList 模块在队列实现中复制构造函数问题
Copy Constructor issue in Queue Implementation using implemented LinkedList module
完整存储库:https://github.com/mervynlee94/queue/tree/master
我已经实现了 LinkedList 并毫无问题地测试了我的复制构造函数。
LinkedList<int> l1;
l1.insert(1,3); // set value 3 in 1st position
l1.insert(2,7); // set value 7 in 2nd position
l1.insert(3,9); // set value 9 in 3rd position
LinkedList<int> l2(l1); // copy constructor
l2.setEntry(2,5); // set value 5 in position 2
cout<< l1.getEntry(2) <<endl; // output: 7
cout<< l2.getEntry(2) <<endl; // output: 5
我的队列实现使用这个 LinkedList 模块作为数据结构,代码如下。
#ifndef _LIST_QUEUE
#define _LIST_QUEUE
#include "QueueInterface.h"
#include "LinkedList.h"
template<class ItemType>
class ListQueue : public QueueInterface<ItemType> {
private :
LinkedList<ItemType> list;
public :
ListQueue();
ListQueue(const ListQueue& aQueue);
~ListQueue();
bool isEmpty() const ;
void enqueue( const ItemType& newEntry);
void dequeue();
ItemType peekFront() const;
};
#endif
template<class ItemType>
ListQueue<ItemType>::ListQueue() {
}
template<class ItemType>
ListQueue<ItemType>::ListQueue(const ListQueue& aQueue) {
list = LinkedList<ItemType>(aQueue.list);
}
template<class ItemType>
ListQueue<ItemType>::~ListQueue() {}
template<class ItemType>
bool ListQueue<ItemType>::isEmpty() const {
return list.isEmpty();
}
template<class ItemType>
void ListQueue<ItemType>::enqueue(const ItemType& newEntry) {
list.insert(list.getLength()+1, newEntry);
}
template<class ItemType>
void ListQueue<ItemType>::dequeue() {
list.remove(1);
}
template<class ItemType>
ItemType ListQueue<ItemType>::peekFront() const {
return list.getEntry(1);
}
当我测试 main.cpp 中的代码时,我遇到了分段错误。
ListQueue<int> q1;
q1.enqueue(1);
q1.enqueue(2);
q1.enqueue(3);
ListQueue<int> q2(q1); // Set breakpoint here
q2.enqueue(5);
cout<<q2.peekFront()<<endl;
cout<<q1.peekFront()<<endl;
我在上面设置了一个调试断点,我意识到一件事。 Queue 实现中的复制构造函数无法正常工作。
aQueue.list 和 this.list 的复制构造函数中显示的调试值不同。
这是LinkedList复制构造函数的实现
template<class ItemType>
LinkedList<ItemType>::LinkedList(const LinkedList<ItemType>& aList) {
Node<ItemType>* listPtr = aList.headPtr;
if(listPtr == nullptr) {
headPtr = nullptr;
}
else {
headPtr = new Node<ItemType>(listPtr->getItem());
Node<ItemType>* newPtr = headPtr;
while(listPtr->getNext() != nullptr) {
listPtr = listPtr->getNext();
Node<ItemType>* newNode = new Node<ItemType>(listPtr->getItem());
newPtr->setNext(newNode);
newPtr = newPtr->getNext();
}
}
itemCount = aList.getLength();
}
请注意,由于 LinkedList 的复制函数已经实现,您不必重新实现它 - C++ 会自动为您完成。
另一个重要的东西——拷贝构造函数和拷贝赋值运算符是distict。
您为您的 Queue 实现了 Copy-ctor,并且在这个 copy-ctor 中使用了复制赋值运算符,我怀疑您没有实现它。
修复它的最简单方法是简单地删除复制构造函数和析构函数,它们不是必需的。调用复制构造函数的正确方法如下:
template<class ItemType>
ListQueue<ItemType>::ListQueue(const ListQueue& aQueue)
: list(aQuquq.list) {
}
我还有三点要说:
- 规则 3 - 如果您声明复制构造函数、复制赋值或析构函数之一,您几乎肯定必须实现它们。
- C++ 中有一个更复杂的特性,叫做 "move semantics",如果您熟悉这个术语,您应该考虑 5 的规则 - 相同作为先前的规则,添加了移动构造函数和移动赋值运算符。
- 您似乎在使用继承,但我在任何地方都没有看到关键字
override
。如果您使用 C++11
或更高版本,请考虑将 override
限定符添加到覆盖方法中。
最后,C++11
支持默认 ctors/dtors 和赋值运算符。如果你写一个空的析构函数(就像你在这里做的那样),更简洁的语法是写
class ListQueue : public QueueInterface<ItemType> {
...
~ListQueue() = default;
...
};
完整存储库:https://github.com/mervynlee94/queue/tree/master
我已经实现了 LinkedList 并毫无问题地测试了我的复制构造函数。
LinkedList<int> l1;
l1.insert(1,3); // set value 3 in 1st position
l1.insert(2,7); // set value 7 in 2nd position
l1.insert(3,9); // set value 9 in 3rd position
LinkedList<int> l2(l1); // copy constructor
l2.setEntry(2,5); // set value 5 in position 2
cout<< l1.getEntry(2) <<endl; // output: 7
cout<< l2.getEntry(2) <<endl; // output: 5
我的队列实现使用这个 LinkedList 模块作为数据结构,代码如下。
#ifndef _LIST_QUEUE
#define _LIST_QUEUE
#include "QueueInterface.h"
#include "LinkedList.h"
template<class ItemType>
class ListQueue : public QueueInterface<ItemType> {
private :
LinkedList<ItemType> list;
public :
ListQueue();
ListQueue(const ListQueue& aQueue);
~ListQueue();
bool isEmpty() const ;
void enqueue( const ItemType& newEntry);
void dequeue();
ItemType peekFront() const;
};
#endif
template<class ItemType>
ListQueue<ItemType>::ListQueue() {
}
template<class ItemType>
ListQueue<ItemType>::ListQueue(const ListQueue& aQueue) {
list = LinkedList<ItemType>(aQueue.list);
}
template<class ItemType>
ListQueue<ItemType>::~ListQueue() {}
template<class ItemType>
bool ListQueue<ItemType>::isEmpty() const {
return list.isEmpty();
}
template<class ItemType>
void ListQueue<ItemType>::enqueue(const ItemType& newEntry) {
list.insert(list.getLength()+1, newEntry);
}
template<class ItemType>
void ListQueue<ItemType>::dequeue() {
list.remove(1);
}
template<class ItemType>
ItemType ListQueue<ItemType>::peekFront() const {
return list.getEntry(1);
}
当我测试 main.cpp 中的代码时,我遇到了分段错误。
ListQueue<int> q1;
q1.enqueue(1);
q1.enqueue(2);
q1.enqueue(3);
ListQueue<int> q2(q1); // Set breakpoint here
q2.enqueue(5);
cout<<q2.peekFront()<<endl;
cout<<q1.peekFront()<<endl;
我在上面设置了一个调试断点,我意识到一件事。 Queue 实现中的复制构造函数无法正常工作。
aQueue.list 和 this.list 的复制构造函数中显示的调试值不同。
这是LinkedList复制构造函数的实现
template<class ItemType>
LinkedList<ItemType>::LinkedList(const LinkedList<ItemType>& aList) {
Node<ItemType>* listPtr = aList.headPtr;
if(listPtr == nullptr) {
headPtr = nullptr;
}
else {
headPtr = new Node<ItemType>(listPtr->getItem());
Node<ItemType>* newPtr = headPtr;
while(listPtr->getNext() != nullptr) {
listPtr = listPtr->getNext();
Node<ItemType>* newNode = new Node<ItemType>(listPtr->getItem());
newPtr->setNext(newNode);
newPtr = newPtr->getNext();
}
}
itemCount = aList.getLength();
}
请注意,由于 LinkedList 的复制函数已经实现,您不必重新实现它 - C++ 会自动为您完成。
另一个重要的东西——拷贝构造函数和拷贝赋值运算符是distict。
您为您的 Queue 实现了 Copy-ctor,并且在这个 copy-ctor 中使用了复制赋值运算符,我怀疑您没有实现它。
修复它的最简单方法是简单地删除复制构造函数和析构函数,它们不是必需的。调用复制构造函数的正确方法如下:
template<class ItemType>
ListQueue<ItemType>::ListQueue(const ListQueue& aQueue)
: list(aQuquq.list) {
}
我还有三点要说:
- 规则 3 - 如果您声明复制构造函数、复制赋值或析构函数之一,您几乎肯定必须实现它们。
- C++ 中有一个更复杂的特性,叫做 "move semantics",如果您熟悉这个术语,您应该考虑 5 的规则 - 相同作为先前的规则,添加了移动构造函数和移动赋值运算符。
- 您似乎在使用继承,但我在任何地方都没有看到关键字
override
。如果您使用C++11
或更高版本,请考虑将override
限定符添加到覆盖方法中。
最后,C++11
支持默认 ctors/dtors 和赋值运算符。如果你写一个空的析构函数(就像你在这里做的那样),更简洁的语法是写
class ListQueue : public QueueInterface<ItemType> {
...
~ListQueue() = default;
...
};