调用析构函数时出错

Error when calling destructor

本文关键字:出错 析构函数 调用      更新时间:2023-10-16

嗨,我正在学习运算符重载..我注意到程序在调用析构函数时崩溃.. 任何帮助不胜感激。谢谢

#include<iostream>
using namespace std;
class Overload
{
private:
    int a, *b;
public:
    Overload():a(0) {cout << "defaultn"; };
    Overload(int x);
    Overload operator+(Overload & rhs);
    int geta();
    int* getb();
    void setb();
    void PrintVals(const Overload & val);
    ~Overload();
};

Overload::Overload( int x)
{
    cout << "Parameterized constructorn";
    a = x;
    b = new int[a];
}

int Overload::geta()
{
    return a;
}

int* Overload::getb()
{
    return b;
}
void Overload::setb()
{
    int val;
    cout << "setting b valuesn";
    for (int i = 0 ; i <= a; i++)
    {
        cin >> val;
        b[i] = val;
    }
}

Overload Overload::operator+(Overload & rhs)
{
    Overload temp;
    temp.a  = this->a + rhs.a;
    temp.b = new int[temp.a];
    *temp.b =  *(this->b) + *(rhs.b);
    cout << "inside overload + vale of LHS:" << *(this->b) << endl;
    cout << "inside overload + vale of RHS:" << *(rhs.b) << endl;
    cout << "inside overload + vale of temp:" << *temp.b << endl;
    cout << "Address of b(temp):" << temp.b << endl;

    temp.b++;
    this->b++;
    rhs.b++;
    *temp.b =  *(this->b) + *(rhs.b);
    cout << "inside overload + vale of LHS:" << *(this->b) << endl;
    cout << "inside overload + vale of RHS:" << *(rhs.b) << endl;
    cout << "inside overload + vale of temp:" << *temp.b << endl;
    cout << "Address of b(temp):" << temp.b << endl;

    return temp;
}

 Overload::~Overload()
 {
 cout << "Destructor n";
 cout << "Address deallocated b:" << b;
 delete [] b;
 }

void Overload::PrintVals(const Overload & val)
{
    int val1, *val2;
    val1 = this->a;
    val2 = this->b;
    cout << "Printing values: a: " << val1 << " b:" << *val2;
}

int main()
{
    Overload X(1),Y(1),Z;
    int val1, *val, val2, val3;
    //Z = X + Y;
    val1 = Y.geta();
    val2 = X.geta();
    Y.setb();

    val = Y.getb();
    printf("val of y  b: %dn",*val);
    printf("val of x  a: %dn",val1);
    X.setb();
    val = X.getb();
    printf("val of x b: %dn",*val);
    printf("val of x a: %dn",val2);

    Z = X + Y;
    val  = Z.getb();
    val3 = Z.geta();
    val--;
    for( int i = 0; i < val3; i++)
    {
        printf("address of (b) Z: %p n",val);
        printf("val of z b: %dn",*val);
        printf("val of z a: %dn",val3);
        val++;
    }
}

输出:。。。破坏者第 1 部分(4815,0x7fff73def300( malloc:* 对象 0x100200004 的错误:未分配正在释放的指针* 在malloc_error_break中设置断点进行调试地址已解除分配 b:0x100200004(lldb(

您还应该实现复制构造函数和赋值运算符。

默认构造函数未初始化b。换句话说,代码不会构造处于有效状态的对象。 当析构函数调用时b可能是任何东西delete[] b这会导致错误 - 你还期待什么?

一个相关的问题是默认构造的复制构造函数和复制赋值运算符将简单地复制b。因此,如果从中复制的对象被销毁,则复制到的对象将留下一个悬空指针,这在其销毁时会导致错误。

主要的教训是:如果你不知道自己在做什么(而且你不知道(,就不要使用原始指针。而是使用std::vectorstd::unique_ptr或标准提供的其他方法,这些方法将为您处理此类事情。

有两个令人讨厌的错误会导致您的错误:

1.缓冲区溢出:

第一个致命错误是缓冲区溢出 setb()b指向一个a元素数组,因此您无法在不损坏内存的情况下设置 b[a]:

for (int i = 0; i < a; i++)  // strictly < a, not <=a !!

2.原始指针的默认副本:

第二个致命错误是在operator+ ()的实现中。 问题是返回temp的副本(调用表达式中匿名临时对象的复制构造(,然后分配给 Z(赋值运算符(:

Overload temp;  // you create a logcal temporary object
...
temp.b = new int[temp.a];  // you allocate the array
...
return b;   // you return a COPY of the temp object 
}           // here the local temp object gets destroyed

但是,由于您既没有定义复制构造函数,也没有定义赋值运算符,因此使用默认运算符。 它们构成了对象的成员副本,即指针只是按原样复制。 结果是Z.b将包含指针temp.b的副本,但temp.b已经在运算符+((的末尾删除了!因此 Z 将引用一个悬空的指针,造成很大的伤害,尤其是在离开 main(( 时,Z 的析构函数将尝试 d 第二次删除它!

创建一个复制构造函数和一个赋值运算符,用于正确分配新的b指针。这将解决第二个问题。

并且,请不要像(this->b++那样增加操作数的指针:它会永久更改 b poitner,并且当操作数超出范围时,删除不会识别它。

顺便说一下,即使它不是问题的直接原因,您也可以通过添加两个操作数的大小来启动temp大小a,但您仅为第一个操作数的大小分配b

3. 其他备注:

默认构造函数不会将b初始化为显式nullptr。 这样做是一种安全的做法,但这不是您在这里遇到的问题的直接原因。

在 operator+(( 中,最好在不访问其内部的情况下初始化 temp:Overload temp (a);将更易于维护且不易出错。

我不知道这是否是你的意图,但只添加了 b 指向的数组的第一个值: *temp.b = *(this->b) + *(rhs.b); 与您使用的最大大小为 1 main()一样,这里不是问题。 但对于将来,最好使用循环来复制所有元素。

最后一句话:你有没有想过你的类的用户可以做一些奇怪的事情,比如:你的运算符+Overload E, G(0), H(1); E = H+G;然后尝试访问空指针?