Ошибка в некоторых из моих функций, касающихся переполнения стека списков

Я использую ICircularDoubleDirectedList для структуры классов, затем мой Список наследует от этого, и этот файл вы можете найти ниже. Я использую файл для проверки глубокого копирования в списке, но дело в том, что он проходит весь тест, кроме того, который находится в конце, где он должен удалить все данные.

Я проверил все свои функции, и они прошли тестирование, поэтому я понятия не имею, где найти решение: /

Я знаю, что это может быть много, и я не могу описать, насколько я был бы счастлив, если бы кто-то помог мне! : D

Это структура дизайна для моего списка:

#ifndef ICDDLIST_H
#define ICDDLIST_Htemplate <typename T>
class ICircularDoubleDirectedList
{
public:
static enum direction{FORWARD, BACKWARD};
virtual ~ICircularDoubleDirectedList() {};                      //gjord
virtual void addAtCurrent(const T& element) = 0;                //gjord
virtual T& getElementAtCurrent() const = 0;                     //gjord
virtual bool removeAtCurrent(const T& element) = 0;
virtual int size() const = 0;                                   //gjord
virtual void changeDirection() = 0;                             //gjord
virtual void moveCurrent() = 0;                                 //gjord
virtual typename direction getCurrentDirection() const = 0;     //gjord
};

#endif

___________________________________________________________________________

Вот мое определение и декларации. Да, я знаю, что они должны быть в двух разных файлах header и .cpp, но мне кажется, что проще проверить, находятся ли они в одном файле.

#ifndef DOUBLELIST_H
#define DOUBLELIST_H

#include "ICircularDoubleDirectedList.h"
using namespace std;

template <typename T>
class CircularDoubleDirectedList : public ICircularDoubleDirectedList <T>{

private:

class Node{
public:

T data;
Node *neighbors[2];

Node(const T& element);
Node(){};
~Node(){};};

direction NodeDirection = FORWARD;
Node *current;
int sizeOfList;

public:

CircularDoubleDirectedList();
CircularDoubleDirectedList(const CircularDoubleDirectedList &other);
~CircularDoubleDirectedList();

virtual void addAtCurrent(const T& element);

T& getElementAtCurrent() const;
bool removeAtCurrent(const T& element);
int size() const;
void changeDirection();
void moveCurrent();
typename direction getCurrentDirection() const;bool operator=(const CircularDoubleDirectedList &other);};template <typename T>
CircularDoubleDirectedList<T>::Node::Node(const T& element){

data = element;

}

template <typename T>
CircularDoubleDirectedList<T>::~CircularDoubleDirectedList(){

if (this->size() != 0){
while (0 < this->sizeOfList){
this->removeAtCurrent(this->getElementAtCurrent());
}
}
//this->current = nullptr;
}

template <typename T>
CircularDoubleDirectedList<T>::CircularDoubleDirectedList(){

NodeDirection = FORWARD;
sizeOfList = 0;
current = nullptr;

}

template <typename T>
CircularDoubleDirectedList<T>::CircularDoubleDirectedList(const CircularDoubleDirectedList &other){

this->NodeDirection = other.NodeDirection;
this->current = other.current;
this->sizeOfList = 0;

if (other.sizeOfList != 0){
Node *counter = other.current;

for (int x = 0; x < other.sizeOfList; x++){
counter = counter->neighbors[BACKWARD];
this->addAtCurrent(counter->data);
}
}
else{
this->current = nullptr;
}

}template <typename T>
void CircularDoubleDirectedList<T>::addAtCurrent(const T& element){

Node *temp = new Node(element);

if (current == nullptr){
current = temp;
temp->neighbors[FORWARD] = temp;
temp->neighbors[BACKWARD] = temp;}

else{
temp->neighbors[FORWARD] = current;
temp->neighbors[BACKWARD] = current->neighbors[BACKWARD];
temp->neighbors[BACKWARD]->neighbors[FORWARD] = temp;

current->neighbors[BACKWARD] = temp;

current = temp;
}

++sizeOfList;

}

template <typename T>
T& CircularDoubleDirectedList<T>::getElementAtCurrent() const{

if (sizeOfList <= 0){
throw "Exeption: call of getElementAtCurrent on empty list";
}

else{
return current->data;
}

}template <typename T>                   //INTE FEL PÅ
bool CircularDoubleDirectedList<T>::removeAtCurrent(const T& element){
bool success = false;

Node *temp = this->current;

int x = 0;
if(sizeOfList <= 0){
throw "Exeption: call of removeAtCurrent on empty list";
}

else if (sizeOfList==1 && current->data==element){
delete current;
this->current = nullptr;
this->sizeOfList--;
success = true;
}

while(x<this->sizeOfList && success==false ) {
if (temp->data == element){
if (temp == this->current){
this->moveCurrent();
}

temp->neighbors[BACKWARD]->neighbors[FORWARD] = temp->neighbors[FORWARD];
temp->neighbors[FORWARD]->neighbors[BACKWARD] = temp->neighbors[BACKWARD];

delete temp;
this->sizeOfList--;
success = true;}
else{
temp = temp->neighbors[FORWARD];
}
x++;
}

return success;
}

template <typename T>
int CircularDoubleDirectedList<T>::size() const{

return sizeOfList;

}

template <typename T>
void CircularDoubleDirectedList<T>::changeDirection(){if (NodeDirection == FORWARD){
NodeDirection = BACKWARD;
}
else
NodeDirection = FORWARD;

}template <typename T>
void CircularDoubleDirectedList<T>::moveCurrent(){

if (NodeDirection == FORWARD && sizeOfList>0){
current = current->neighbors[FORWARD];
}
else if (NodeDirection == BACKWARD && sizeOfList>0){
current = current->neighbors[BACKWARD];
}
else{
throw "Exception: call of moveCurrent on empty list";
}
}

template <typename T>
typename ICircularDoubleDirectedList<T>::direction CircularDoubleDirectedList<T>::getCurrentDirection() const{

return NodeDirection;

}template <typename T>   //inte fel på
bool CircularDoubleDirectedList<T>::operator=(const CircularDoubleDirectedList &other){if (&other == this){
return true;
}

if (this->size() != 0){
Node *temp1 = this->current;
T temp2;

while (0 < this->sizeOfList){
temp2 = temp1->data;
temp1 = temp1->neighbors[FORWARD];
this->removeAtCurrent(temp2);
}
this->current = nullptr;
}

this->NodeDirection = other.NodeDirection;

if (other.size() > 0){

Node *counter = other.current;

for (int x = 0; x < other.size(); x++){
counter = counter->neighbors[BACKWARD];
this->addAtCurrent(counter->data);
}
}
else{
this->current = nullptr;
}

return true;

}#endif

И это файл, который я использую для проверки моего списка:

#include "CircularDoubleDirectedList.h"#include <iostream>

using namespace std;
template <typename T>
void printList(CircularDoubleDirectedList<T>& list)
{
for (int i=0; i<list.size(); i++)
{
cout<<list.getElementAtCurrent()<<" ";
list.moveCurrent();
}
}

template <typename T>
void test(CircularDoubleDirectedList<T> list)
{
list.addAtCurrent(55);
}

int main()
{
_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
CircularDoubleDirectedList<int> aList;
CircularDoubleDirectedList<int> bList = aList;

cout<<"******** Testing copy constructor on empty list ********"<<endl;
cout<<endl<<"Expected output: \nElements in aList: \nElements in bList"<<endl<<endl<<"Your output: "<<endl;
cout<<"Elements in aList ";
printList(aList);

cout<<endl<<"Elements in bList ";
printList(bList);
cout<<endl;
system("pause");
cout<<endl<<"******** Testing copy constructor on list with content ********"<<endl;

aList.addAtCurrent(10);
aList.addAtCurrent(20);

CircularDoubleDirectedList<int> cList = aList;

cout<<endl<<"Expected output: \nElements in aList 20 10\nElements in cList 20 10"<<endl<<endl<<"Your output: "<<endl;
cout<<"Elements in aList ";
printList(aList);

cout<<endl<<"Elements in cList ";
printList(cList);

aList.removeAtCurrent(20);
cList.addAtCurrent(5);

cout<<endl<<endl<<"Expected output: \nElements in cList 5 20 10"<<endl<<endl<<"Your output: "<<endl;

test(cList);

cout<<"Elements in cList ";
printList(cList);

cout<<endl;
system("pause");

CircularDoubleDirectedList<int> dList;
CircularDoubleDirectedList<int> eList;cout<<endl<<endl<<"******** Testing assignment operator on empty list ********"<<endl;
dList = eList;
cout<<endl<<"Expected output: \nElements in dList \nElements in eList"<<endl<<endl<<"Your output: "<<endl;
cout<<"Elements in dList ";
printList(dList);

cout<<endl<<"Elements in eList ";
printList(eList);
cout<<endl;
system("pause");

cout<<endl<<endl<<"**** Testing assignment operator on list with content assigned empty list****"<<endl;
eList.addAtCurrent(20);
eList.addAtCurrent(10);

eList = dList;

cout<<endl<<"Expected output: \nElements in dList\nElements in eList"<<endl<<endl<<"Your output: "<<endl;
cout<<"Elements in dList ";
printList(dList);

cout<<endl<<"Elements in eList ";
printList(eList);
cout<<endl;
system("pause");
cout<<endl;

cout<<endl<<"***** Testing assignment operator on empty list assigned list with content *****"<<endl;
eList.addAtCurrent(20);
eList.addAtCurrent(10);

dList = eList;

cout<<"Expected output: \nElements in dList 10 20 \nElements in eList 10 20"<<endl<<endl<<"Your output: "<<endl;
cout<<"Elements in dList ";
printList(dList);

cout<<endl<<"Elements in eList ";
printList(eList);
cout<<endl;

system("pause");

dList.addAtCurrent(5);
eList.removeAtCurrent(20);
cout<<endl<<"Expected output: \nElements in dList 5 10 20 \nElements in eList 10"<<endl<<endl<<"Your output: "<<endl<<endl;
cout<<"Elements in dList ";
printList(dList);

cout<<endl<<"Elements in eList ";
printList(eList);
cout<<endl;
system("pause");

cout<<endl<<"***** Testing assignment operator on lists with content *****"<<endl;

eList = dList;

cout<<"Expected output: \nElements in dList 5 10 20 \nElements in eList 5 10 20"<<endl<<endl<<"Your output: "<<endl;
cout<<"Elements in dList ";
printList(dList);

cout<<endl<<"Elements in eList ";
printList(eList);
cout<<endl;

system("pause");

eList.addAtCurrent(1);
dList.removeAtCurrent(10);

cout<<endl;
cout<<"Expected output: \nElements in dList 5 20 \nElements in eList 1 5 10 20"<<endl<<endl<<"Your output: "<<endl;
cout<<"Elements in dList ";
printList(dList);

cout<<endl<<"Elements in eList ";
printList(eList);
cout<<endl;

system("pause");

cout<<endl<<"***** Testing assignment operator on a list assigned itself *****"<<endl;

dList = dList;

cout<<endl<<"Expected output: \nElements in dList 5 20 "<<endl<<endl<<"Your output: "<<endl;
cout<<"Elements in dList ";
printList(dList);
cout<<endl;

system("pause");cout<<endl<<"***** Testing destructor of list *****"<<endl;ICircularDoubleDirectedList<int>* fList = new CircularDoubleDirectedList<int>();fList->addAtCurrent(100);
fList->addAtCurrent(50);delete fList;               //NÅgot fel här

return 0;
}

0

Решение

Есть несколько проблем с вашим кодом

Первый основан на стиле. Нет необходимости указывать this-> во всех строках вы ссылаетесь на текущий объект. Это запутывает код и не является необходимым.

Во-вторых, вы написали свои операторы копирования / присваивания неправильно и в плохом стиле. Тем не менее, я хотел бы отдать вам должное за написание вашего конструктора копирования с помощью addAtCurrent функция. Обычно я вижу людей, пишущих конструктор копирования со всевозможной логикой указателя, дублирующий код, который они уже написали в add функцию члена они написали. Вы не совершили эту ошибку, поэтому я благодарю вас за это.

Ваш конструктор копирования для CircularDoubledirectList не нужно делать никаких if заявления. Всякий раз, когда я вижу if операторы в конструкторе копирования, который выделяет красный флаг. Если в конструкторе копирования слишком много логики, основанной на принятии решений, есть большая вероятность, что получится не настоящая копия, а полусгоревшая копия. Полуиспеченные копии, плавающие в программе, являются ошибками, которые очень трудно найти, так как это может привести к возникновению неопределенного поведения.

Итак, вот переписать конструктор копирования без использования if:

template <typename T>
CircularDoubleDirectedList<T>::CircularDoubleDirectedList(const CircularDoubleDirectedList &other) :
NodeDirection(other.NodeDirection),
sizeOfList(0), current(nullptr)
{
Node *counter = other.current;
for (int x = 0; x < other.sizeOfList; ++x)
{
counter = counter->neighbors[BACKWARD];
addAtCurrent(counter->data);
}
}

Код выше использует member initialization list инициализировать определенные элементы их «пустыми» значениями. Обратите внимание, что цикл не проверяет размер — в этом нет необходимости. Если размер other 0, то цикл не выполняется.

Теперь, учитывая вышесказанное, давайте перепишем оператор присваивания в терминах конструктора копирования. Огромная проблема с вашей текущей реализацией оператора присваивания заключается в том, что вы возвращаете bool, То, что вы должны возвращать, является ссылкой на CircularDoubleDirectedList,

Вторая проблема с оператором присваивания заключается в том, что он является избыточным. Весь код, который вы написали, уже находится в конструкторе копирования. Я бы это исправил, используя copy/swap idiomгде вы будете использовать конструктор копирования, чтобы «помочь» с назначением.

Вот реализация использования этой идиомы:

#include <algorithm>
//...
template <typename T>
class CircularDoubleDirectedList : public ICircularDoubleDirectedList <T>{
private:
void swap(CircularDoubleDirectedList<T>& left,
CircularDoubleDirectedList<T>& right);
//...
};
//...
template <typename T>
void CircularDoubleDirectedList<T>::swap(CircularDoubleDirectedList<T>& left, CircularDoubleDirectedList<T>& right)
{
std::swap(left.NodeDirection, right.NodeDirection);
std::swap(left.current, right.current);
std::swap(left.sizeOfList, right.sizeOfList);
}

template <typename T>
CircularDoubleDirectedList<T>& CircularDoubleDirectedList<T>::operator=(const CircularDoubleDirectedList &other)
{
CircularDoubleDirectedList<T> temp(other);
swap(*this, temp);
return *this;
}

Так что здесь произошло? Ну, все, что я сделал, это использовал конструктор копирования для создания временного объекта. Тогда я позвонил swap функция для переключения переменных между временной копией и * this. Потом возвращаю текущий объект (this). Это не только проверяет конструктор копирования, деструктор для temp также проверено. Поэтому, если в конструкторе или деструкторе копирования есть какие-либо ошибки, вы можете обнаружить их прямо здесь.

Я добавил swap функция для вызова std::swap это переключает каждого из членов.

Поскольку ваш код проверяет оператор присваивания, и вы не правильно его реализовали с правильным типом возврата, измените код на приведенный выше и повторите тест.

С изменениями, указанными выше, я не столкнулся с проблемами повреждения памяти, и программа успешно завершилась. Нельзя сказать, что где-то может и не быть ошибки (я не проходил логику добавления и удаления элементов), но у меня не было проблем с запуском кода после внесения изменений в вашу программу.

1

Другие решения