Проблема копирования конструктора в реализации очереди с использованием реализованного модуля LinkedList - PullRequest
0 голосов
/ 12 апреля 2020

Полный репозиторий: 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

Реализация My Queue использует этот модуль 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;

Я установил точку останова отладки выше и понял одну вещь. Конструктор копирования в реализации очереди не работает должным образом.

Значение отладки, отображаемое в конструкторе копирования aQueue.list и this.list, различается. Debugging values

Вот реализация конструктора копирования 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();
}

1 Ответ

1 голос
/ 12 апреля 2020

Обратите внимание, что поскольку copy-ctor LinkedList уже реализован, вам не нужно переопределять его - C ++ сделает это автоматически за вас.

Другая важная вещь - копия конструктор и оператор присваивания копии distict .

Вы реализовали Copy-ctor для своей очереди, и в этом copy-ctor вы использовали оператор назначения копирования, и я подозреваю, что вы не реализовали его.

Самый простой способ исправить это это просто удалить конструктор копирования и деструктор, они не нужны. Правильный способ вызова конструктора копирования заключается в следующем:


template<class ItemType>
ListQueue<ItemType>::ListQueue(const ListQueue& aQueue) 
    : list(aQuquq.list) {
}

У меня есть еще три момента, которые нужно сделать:

  1. Правило 3 - если вы объявляете один из конструктор, копирование-присваивание или деструктор, вы почти наверняка должны реализовать их все.
  2. В C ++ есть немного более сложная функция, называемая "семантикой перемещения", в случае, если вы знакомы с этим термином, вы должны рассмотреть Правило 5 - то же, что и в предыдущем правиле, с добавлением конструктора перемещения и оператора присваивания перемещения.
  3. Кажется, что вы используете наследование, но я не см. ключевое слово override в любом месте. Если вы используете C++11 или выше, рассмотрите возможность добавления квалификатора override к переопределяющим методам.

И, наконец, C++11 поддерживает стандартные ctors / dtors и операторы присваивания. Если вы напишите пустой деструктор (как вы делаете здесь), синтаксис очистки будет писать

class ListQueue : public QueueInterface<ItemType> {
        ...
        ~ListQueue() = default;
        ...
};
...