我的一些关于List C ++的函数出错了

时间:2014-09-20 18:43:36

标签: c++ list inheritance copying

我使用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;
}

1 个答案:

答案 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来切换每个成员。

由于您的代码测试了赋值运算符,并且没有使用正确的返回类型正确实现它,请将代码更改为上面的代码并重新测试。

通过上述更改,我没有遇到任何内存损坏问题,程序已成功完成。并不是说某处可能没有错误(我没有通过添加和删除项目的逻辑),但在应用程序的更改完成后,我没有遇到运行代码的问题。