即使是复制分配运算符也无法提供帮助

Even the Copy Assignment Operator can't assist

本文关键字:帮助 复制 分配 运算符 即使是      更新时间:2023-10-16

请帮我找出问题所在。我也遵循了三法则,并对代码进行了一些修改。

#include <iostream>
using namespace std;
class AStack {
    public:
        AStack();
        AStack(int);
        AStack(const AStack&);
        ~AStack();
        AStack& operator = (const AStack& s);
        void push(int);
        int pop();
        int top();
        bool isEmpty();
        void flush();
    private:
        int capacity ;
        int* a;
        int index = -1; // Index of the top most element
};
AStack::AStack() {
    a = new int[25];
    capacity = 25;
}
AStack::AStack(int size) {
    a = new int[size];
    capacity = size;
}
AStack::AStack(const AStack& s) {
    capacity = s.capacity;
    delete[] a; // To avoid memory leak
    a = new int[capacity];
    for (int i = 0; i < capacity; i++) { 
        a[i] = s.a[i];
    }
    index = s.index;
}
AStack::~AStack() {
    delete[] a;
}
AStack& AStack::operator = (const AStack& s) {
    capacity = s.capacity;
    delete[] a; // To avoid memory leak
    int* a = new int[capacity];
    for (int i = 0; i < capacity; i++) {
        a[i] = s.a[i];
    }
    index = s.index;
    return *this;
}
void AStack::push(int x) {
    if (index == capacity - 1) {
        cout << "nnThe stack is full. Couldn't insert " << x << "nn";
        return;
    }
    a[++index] = x;
}
int AStack::pop() {
    if (index == -1) {
        cout << "nnNo elements to popnn";
        return -1;
    }
    return a[index--];
}
int AStack::top() {
    if (index == -1) {
        cout << "nnNo elements in the Stacknn";
        return -1;
    }
    return a[index];
}
bool AStack::isEmpty() {
    return (index == -1);
}
void AStack::flush() {
    if (index == -1) {
        cout << "nnNo elements in the Stack to flushnn";
        return;
    }
    cout << "nnFlushing the Stack:  ";
    while (index != -1) {
        cout << a[index--] << "  ";
    }
    cout << endl << endl;
}
AStack& reverseStack(AStack& s1) {
    AStack s2;
    while (!s1.isEmpty()) {
        s2.push(s1.pop());
    }
    s1 = s2;
    return s1;
}
int main() {
    AStack s1;
    s1.push(1);
    s1.push(2);
    s1.push(3);
    s1.push(4);
    s1.push(5);
    s1 = reverseStack(s1);
    cout << "nnFlushing s1:n";
    s1.flush();
    system("pause");
    return 0;
}

我不明白即使在定义了适当的复制赋值运算符之后,从函数返回后 s1 中的值也是垃圾值。

如果你的复制构造函数是正确的,并且你的析构函数是正确的,你的赋值运算符可以以更简单、更安全的方式编写。

目前,赋值运算符有两个主要缺陷:

  1. 不检查自我分配。
  2. this在知道可以成功分配内存(您的代码不是异常安全的)。

出错的原因是对 reverseStack 的调用返回对当前对象的引用。 这将调用赋值运算符,因此赋值运算符将当前对象分配给当前对象。 因此,上述问题1被触发。

你删除自己,

然后重新分配自己,但是你从哪里得到循环中的值来分配? 它们被删除了,因此它们是垃圾。

对于上面的第 2 项,这些行会在分配内存之前更改this

capacity = s.capacity;
delete[] a; // To avoid memory leak

如果对new[]的调用引发异常,会发生什么情况? 您不仅通过更改容量值弄乱了对象,而且还通过过早调用delete[]销毁了对象中的数据。

另一个问题(需要修复以在答案后面使用复制/交换习惯用法)是你的复制构造函数正在释放它从未分配的内存:

AStack::AStack(const AStack& s) {
    capacity = s.capacity;
    delete[] a;  // ??  What

删除带有delete[] a的行,因为您很可能在指向垃圾的指针上调用delete[]

现在,为了摆脱赋值运算符的这些问题,应该使用复制/交换习惯用法。 这需要一个工作副本构造函数和一个工作析构函数,然后才能使用此方法。 这就是为什么我们需要在继续之前先修复您的复制构造函数。

#include <algorithm>
//...
AStack& AStack::operator = (AStack s) 
{
    std::swap(capacity, s.capacity);
    std::swap(a, s.a);
    std::swap(index, s.index);
    return *this;
}
请注意,我们

不需要检查自赋值,因为按值传递的对象是一个全新的临时对象,我们从中获取值,而不是当前对象的值(同样,这是原始代码失败的原因)。

此外,如果new[]抛出异常,则在创建按值传递的临时对象时,将在调用赋值运算符时引发异常。 因此,我们永远不会有机会因为抛出异常而无意中弄乱我们的对象new[]

请阅读copy/swap习语是什么,以及为什么这是编写赋值运算符的最简单、最安全和最可靠的方法。 这个答案详细解释了你需要知道什么:

什么是复制和交换成语?

下面是固定代码的实时示例。 请注意,还有其他更改,例如删除默认构造函数并使Attack(int)析构函数采用默认参数 25。

现场示例:http://ideone.com/KbA20D