我使用 ICircularDoubleDirectedList 作为类结构,然后我的列表继承自这个和那个文件,你可以在下面找到。我使用一个文件来测试列表中的深度复制,但问题是它通过了所有测试,除了最后一个应该删除所有数据的测试。
我已经测试了我所有的功能,它们都通过了测试,所以我不知道在哪里可以找到解决方案:/
我知道这可能需要看很多东西,如果有人能帮助我,我真的无法形容我会有多高兴! :D
这是我的列表的设计结构:
#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;
}
最佳答案
你的代码有几个问题
第一个是基于样式的。无需在引用当前对象的所有行中指定 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);
}
}
上面的代码使用成员初始化列表
将某些成员初始化为它们的“空”值。请注意,循环不检查大小——没有必要。如果 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
来切换每个成员。
由于您的代码测试了赋值运算符,而您没有使用正确的返回类型正确实现它,请将您的代码更改为上面的代码并再次测试。
通过上述更改,我没有遇到任何内存损坏问题,程序成功完成。并不是说某处可能没有错误(我没有完成添加和删除项目的逻辑),但在对您的程序进行更改后,我运行代码时没有遇到任何问题。
关于c++ - 我的一些关于 List C++ 的函数有问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25952149/