【问题标题】:Destructor array stack tiwer hanoi c++ double pointer析构函数数组堆栈tiwer hanoi c ++双指针
【发布时间】:2021-11-28 18:18:31
【问题描述】:

我尝试将元素压入堆栈,但显示空间量错误。如果长度大于容量,容量会升级。有人知道如何纠正这个错误吗?我认为这可能来自析构函数,但我对此不太确定。

ArrayStack.cpp

#include "ArrayStack.h"

ArrayStack::ArrayStack() 
{
   maxCapacity = DEFAULT_CAPACITY;
   this->tab = new int* [DEFAULT_CAPACITY];
   this->topElement = 0;
   this->length = 0;
}

ArrayStack::~ArrayStack()
{
    for (int i = 0; i < maxCapacity; i++)
    {
        delete tab[i];
    }
    delete[] tab;
}

void ArrayStack::push(int element)
{
    this->length++;
    while (this->maxCapacity <= this->length) {
        maxCapacity += DEFAULT_CAPACITY;

        int** temp = new int* [maxCapacity];
        for (int i = 0; i < maxCapacity; i++)
        {
            temp[i] = tab[i];
        }
        delete tab;
        this->tab = temp;
    }
   
    this->tab[this->length] = new int (element);
    this->topElement = element;
    
}

void ArrayStack::pop()
{
    if (isEmpty())
    {
        throw Empty_Stack();
    }
    delete tab[this->length];

    this->length--;
    if (isEmpty())
    {
        this->topElement = -1;
    }
    else 
    {
        this->topElement = *tab[this->length];
    }


}

int ArrayStack::top() const
{
    if (isEmpty())
    {
        throw Empty_Stack();
    }
    return this->topElement;

}

bool ArrayStack::isEmpty() const
{
    if (this->length == 0)
    {
        return true;
    }
    return false;
}

int ArrayStack::size() const
{
    return this->length;
}

ArrayStack.h

#pragma once
#include "Stack.h"
#include "NotImplementedException.h"
class ArrayStack : public Stack
{
public:
    static const int DEFAULT_CAPACITY = 10;

    // ATTENTION, pour chacune des méthodes, lorsque
    // vous créez sa définition dans le .cpp, vous devez
    // remplacer {} (et éventuellement son contenu) par un ;
    ArrayStack();
    ~ArrayStack();
    void push(int element) override;
    void pop() override;
    int top() const override; 
    bool isEmpty() const override;
    int size() const override;

private:
    int length;
    int** tab;
    int topElement;
    int maxCapacity;

};

【问题讨论】:

    标签: c++ arrays stack destructor towers-of-hanoi


    【解决方案1】:

    我发现这个类管理其数组的方式有很多问题:

    • 构造函数正在分配一个int* 指针数组,但最初并未将它们中的任何一个设置为nullptr。这会导致析构函数出现问题,因为它在每个指针上调用delete,无论它们是否已被初始化。为了避免delete未使用的指针,析构函数应该循环到length,而不是maxCapacity

    • 同样,pop() 没有设置任何指向nullptr 的释放指针,这也会导致析构函数在循环到maxCapacity 而不是length 时出现问题。这也是delete'ing 错误的数组元素,如果数组达到其最大容量,则会超出范围。

    • push() 分配一个新数组时(仅供参考,外部while 循环是不必要的),它从旧数组中复制了太多元素,而旧数组比新数组小。此外,它使用delete 而不是delete[] 来释放旧数组。

    • 该类没有遵循Rule of 3/5/0,因为它应该实现(或至少禁用)复制/移动构造函数和复制/移动赋值运算符。

    尝试类似的方法:

    ArrayStack.h

    #pragma once
    #include "Stack.h"
    #include "NotImplementedException.h"
    
    class ArrayStack : public Stack
    {
    public:
        static const int DEFAULT_CAPACITY = 10;
    
        // ATTENTION, pour chacune des méthodes, lorsque
        // vous créez sa définition dans le .cpp, vous devez
        // remplacer {} (et éventuellement son contenu) par un ;
    
        ArrayStack();
        ArrayStack(const ArrayStack &src);
        ArrayStack(ArrayStack &&src);
        ~ArrayStack();
    
        ArrayStack& operator=(ArrayStack rhs);
    
        void push(int element) override;
        void pop() override;
        int top() const override; 
        bool isEmpty() const override;
        int size() const override;
    
    private:
        int length;
        int** tab;
        int topElement;
        int maxCapacity;
    };
    

    ArrayStack.cpp

    #include "ArrayStack.h"
    #include <utility>
    
    ArrayStack::ArrayStack() 
    {
       maxCapacity = DEFAULT_CAPACITY;
       tab = new int* [DEFAULT_CAPACITY];
       for (int i = 0; i < DEFAULT_CAPACITY; ++i) {
          tab[i] = nullptr;
       }
       length = 0;
       topElement = -1;
    }
    
    ArrayStack::ArrayStack(const ArrayStack &src)
    {
       maxCapacity = src.maxCapacity;
       tab = new int* [maxCapacity];
       for (int i = 0; i < src.length; ++i) {
          tab[i] = new int (*(src.tab[i]));
       }
       for (int i = src.length; i < maxCapacity; ++i) {
          tab[i] = nullptr;
       }
       length = src.length;
       topElement = src.topElement;
    }
    
    ArrayStack::ArrayStack(ArrayStack &&src)
    {
       maxCapacity = src.maxCapacity; src.maxCapacity = 0;
       tab = src.tab; src.tab = nullptr;
       length = src.length; src.length = 0;
       topElement = src.topElement; src.topElement = -1;
    }
    
    ArrayStack& ArrayStack::operator=(ArrayStack rhs)
    {
        std::swap(maxCapacity, rhs.maxCapacity);
        std::swap(tab, rhs.tab);
        std::swap(length, rhs.length);
        std::swap(topElement, rhs.topElement);
        return *this;
    }
    
    ArrayStack::~ArrayStack()
    {
        for (int i = 0; i < length; ++i) {
            delete tab[i];
        }
        delete[] tab;
    }
    
    void ArrayStack::push(int element)
    {
        if (maxCapacity <= length) {
            int newCapacity = maxCapacity + DEFAULT_CAPACITY;
    
            int** temp = new int* [newCapacity];
            for (int i = 0; i < length; ++i) {
                temp[i] = tab[i];
            }
            for (int i = length; i < newCapacity; ++i) {
                temp[i] = nullptr;
            }
    
            delete[] tab;
            tab = temp;
            maxCapacity = newCapacity;
        }
       
        tab[length] = new int (element);
        ++length;
    
        topElement = element;
    }
    
    void ArrayStack::pop()
    {
        if (isEmpty()) {
            throw Empty_Stack();
        }
    
        --length;
        delete tab[length];
        tab[length] = nullptr;
    
        if (isEmpty()) {
            topElement = -1;
        }
        else {
            topElement = *tab[length-1];
        }
    }
    
    int ArrayStack::top() const
    {
        if (isEmpty()) {
            throw Empty_Stack();
        }
        return topElement;
    }
    
    bool ArrayStack::isEmpty() const
    {
        return (length == 0);
    }
    
    int ArrayStack::size() const
    {
        return length;
    }
    

    Online Demo


    话虽如此,完全没有充分的理由使用int* 指针数组。您应该改用 int 值的数组。这样你手动管理的东西就会少一点:

    ArrayStack.h

    #pragma once
    #include "Stack.h"
    #include "NotImplementedException.h"
    
    class ArrayStack : public Stack
    {
    public:
        static const int DEFAULT_CAPACITY = 10;
    
        // ATTENTION, pour chacune des méthodes, lorsque
        // vous créez sa définition dans le .cpp, vous devez
        // remplacer {} (et éventuellement son contenu) par un ;
    
        ArrayStack();
        ArrayStack(const ArrayStack &src);
        ArrayStack(ArrayStack &&src);
        ~ArrayStack();
    
        ArrayStack& operator=(ArrayStack rhs);
    
        void push(int element) override;
        void pop() override;
        int top() const override; 
        bool isEmpty() const override;
        int size() const override;
    
    private:
        int length;
        int* tab;
        int topElement;
        int maxCapacity;
    };
    

    ArrayStack.cpp

    #include "ArrayStack.h"
    #include <utility>
    
    ArrayStack::ArrayStack() 
    {
       maxCapacity = DEFAULT_CAPACITY;
       tab = new int [DEFAULT_CAPACITY];
       length = 0;
       topElement = -1;
    }
    
    ArrayStack::ArrayStack(const ArrayStack &src)
    {
       maxCapacity = src.maxCapacity;
       tab = new int [maxCapacity];
       for (int i = 0; i < src.length; ++i) {
          tab[i] = src.tab[i];
       }
       length = src.length;
       topElement = src.topElement;
    }
    
    ArrayStack::ArrayStack(ArrayStack &&src)
    {
       maxCapacity = src.maxCapacity; src.maxCapacity = 0;
       tab = src.tab; src.tab = nullptr;
       length = src.length; src.length = 0;
       topElement = src.topElement; src.topElement = -1;
    }
    
    ArrayStack& ArrayStack::operator=(ArrayStack rhs)
    {
        std::swap(maxCapacity, rhs.maxCapacity);
        std::swap(tab, rhs.tab);
        std::swap(length, rhs.length);
        std::swap(topElement, rhs.topElement);
        return *this;
    }
    
    ArrayStack::~ArrayStack()
    {
        delete[] tab;
    }
    
    void ArrayStack::push(int element)
    {
        if (maxCapacity <= length) {
            int newCapacity = maxCapacity + DEFAULT_CAPACITY;
    
            int* temp = new int [newCapacity];
            for (int i = 0; i < length; ++i) {
                temp[i] = tab[i];
            }
    
            delete[] tab;
            tab = temp;
            maxCapacity = newCapacity;
        }
       
        tab[length] = element;
        ++length;
    
        topElement = element;
    }
    
    void ArrayStack::pop()
    {
        if (isEmpty()) {
            throw Empty_Stack();
        }
    
        --length;
    
        if (isEmpty()) {
            topElement = -1;
        }
        else {
            topElement = tab[length-1];
        }
    }
    
    int ArrayStack::top() const
    {
        if (isEmpty()) {
            throw Empty_Stack();
        }
        return topElement;
    }
    
    bool ArrayStack::isEmpty() const
    {
        return (length == 0);
    }
    
    int ArrayStack::size() const
    {
        return length;
    }
    

    Online Demo

    在这种情况下,更好的选择是用 std::vector 替换手动数组,让它为您完成所有繁重的工作:

    ArrayStack.h

    #pragma once
    #include "Stack.h"
    #include "NotImplementedException.h"
    #include <vector>
    
    class ArrayStack : public Stack
    {
    public:
        static const int DEFAULT_CAPACITY = 10;
    
        // ATTENTION, pour chacune des méthodes, lorsque
        // vous créez sa définition dans le .cpp, vous devez
        // remplacer {} (et éventuellement son contenu) par un ;
    
        ArrayStack();
    
        void push(int element) override;
        void pop() override;
        int top() const override; 
        bool isEmpty() const override;
        int size() const override;
    
    private:
        std::vector<int> tab;
        int topElement;
    };
    

    ArrayStack.cpp

    #include "ArrayStack.h"
    
    ArrayStack::ArrayStack() 
    {
       tab.reserve(DEFAULT_CAPACITY);
       topElement = -1;
    }
    
    void ArrayStack::push(int element)
    {
        tab.push_back(element);
        topElement = element;
    }
    
    void ArrayStack::pop()
    {
        if (isEmpty()) {
            throw Empty_Stack();
        }
    
        tab.pop_back();
    
        if (tab.empty()) {
            topElement = -1;
        }
        else {
            topElement = tab.back();
        }
    }
    
    int ArrayStack::top() const
    {
        if (isEmpty()) {
            throw Empty_Stack();
        }
        return topElement;
    }
    
    bool ArrayStack::isEmpty() const
    {
        return tab.empty();
    }
    
    int ArrayStack::size() const
    {
        return tab.size();
    }
    

    Online Demo

    然后,最后,改用std::stack

    ArrayStack.h

    #pragma once
    #include "Stack.h"
    #include "NotImplementedException.h"
    #include <stack>
    
    class ArrayStack : public Stack
    {
    public:
        // ATTENTION, pour chacune des méthodes, lorsque
        // vous créez sa définition dans le .cpp, vous devez
        // remplacer {} (et éventuellement son contenu) par un ;
    
        void push(int element) override;
        void pop() override;
        int top() const override; 
        bool isEmpty() const override;
        int size() const override;
    
    private:
        std::stack<int> tab;
    };
    

    ArrayStack.cpp

    #include "ArrayStack.h"
    
    void ArrayStack::push(int element)
    {
        tab.push(element);
    }
    
    void ArrayStack::pop()
    {
        if (isEmpty()) {
            throw Empty_Stack();
        }
    
        tab.pop();
    }
    
    int ArrayStack::top() const
    {
        if (isEmpty()) {
            throw Empty_Stack();
        }
        return tab.top();
    }
    
    bool ArrayStack::isEmpty() const
    {
        return tab.empty();
    }
    
    int ArrayStack::size() const
    {
        return tab.size();
    }
    

    Online Demo

    看看清洁度有多高? :-)

    【讨论】:

    • 那么它应该是什么样子?我没有瘦 3/5/0 但你能给我解决方案吗?
    • 抱歉,你能告诉我它应该是什么样子吗?
    • 你能告诉我它应该是什么样子吗,因为我不明白
    • 我的老师让我使用 int** 但除了第一个之外没有运算符和其他构造函数
    • @NicolasPellerin 刷新页面查看最新代码。至于你的老师,坚持使用 int* 指针数组,而忽略 3/5/0 规则,并没有教给你良好的 C++ 习惯。
    猜你喜欢
    • 2022-01-20
    • 2022-01-01
    • 2016-08-18
    • 2020-01-03
    • 2013-10-19
    • 2019-06-20
    • 2018-04-21
    • 2011-06-12
    • 2013-04-03
    相关资源
    最近更新 更多