我使用ICircularDoubleDirectedList作为类结构,然后我的List继承自此文件,你可以找到更远的文件。我使用一个文件来测试列表中的深层复制,但问题是它通过了所有测试,除了它应该删除所有数据的最后一个。
我已经测试了我的所有功能并且通过了测试,因此我不知道在哪里可以找到解决方案:/
我知道这可能有很多东西要看,如果有人能帮助我的话我无法形容我会多么开心! :d
这是我的List的设计结构:
#ifndef ICDDLIST_H
#define ICDDLIST_H
template <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
___________________________________________________________________________
这是我的定义和声明。是的,我知道它们应该在两个不同的标题和.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 :(得分:1)
您的代码有几个问题
第一种是基于风格的。无需在引用当前对象的所有行中指定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
将某些成员初始化为他们的&#34;空&#34;值。请注意,循环不会检查大小 - 没有必要。如果other
的大小为0,则循环不会执行。
现在给出上述内容,让我们根据复制构造函数重写赋值运算符。您当前执行赋值运算符的一个巨大问题是您返回bool
。你应该返回的是对CircularDoubleDirectedList
的引用。
赋值运算符的第二个问题是它是多余的。您编写的所有代码都已存在于复制构造函数中。我修复它的方法是使用copy/swap idiom
,你将使用复制构造函数来帮助&#34;与任务。
以下是使用此习语的实现:
#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
函数来切换temp副本和* this之间的变量。然后我返回当前对象(this
)。这不仅测试了复制构造函数,还测试了temp
的析构函数。因此,如果复制构造函数或析构函数中存在任何错误,您可以在此处检测到它们。
我添加了一个swap
函数来调用std::swap
来切换每个成员。
由于您的代码测试了赋值运算符,并且没有使用正确的返回类型正确实现它,请将代码更改为上面的代码并重新测试。
通过上述更改,我没有遇到任何内存损坏问题,程序已成功完成。并不是说某处可能没有错误(我没有通过添加和删除项目的逻辑),但在应用程序的更改完成后,我没有遇到运行代码的问题。