调用析构函数时出错

时间:2014-11-30 21:39:09

标签: c++

您好我正在学习运算符重载...我注意到程序在调用析构函数时崩溃..任何帮助表示赞赏。 感谢

#include<iostream>
using namespace std;

class Overload
{
private:
    int a, *b;
public:
    Overload():a(0) {cout << "default\n"; };
    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 constructor\n";
    a = x;
    b = new int[a];
}


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


int* Overload::getb()
{
    return b;
}

void Overload::setb()
{
    int val;
    cout << "setting b values\n";
    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: %d\n",*val);
    printf("val of x  a: %d\n",val1);

    X.setb();

    val = X.getb();
    printf("val of x b: %d\n",*val);
    printf("val of x a: %d\n",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: %d\n",*val);
        printf("val of z a: %d\n",val3);
        val++;

    }

}

输出:... 析构函数 Part1(4815,0x7fff73def300)malloc: *对象0x100200004的错误:未释放指针被释放 * 在malloc_error_break中设置断点以进行调试 地址解除分配b:0x100200004(lldb)

3 个答案:

答案 0 :(得分:4)

您还应该实施copy constructorassignment operator

答案 1 :(得分:3)

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

1.缓冲溢出:

第一个致命错误是setb()中的缓冲区溢出:b指向a个元素的数组,因此您无法设置b [a]而不会有损坏内存的风险:< / p>

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的析构函数将尝试dto第二次删除它!

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

并且请不要像你(this->b++那样递增操作数的指针:它改变了b poitner for good,而当操作数超出范围时,delete将无法识别它。

顺便说一下,即使它不是问题的直接原因,也可以通过添加两个操作数的大小来temp大小a,但是你分配{{ 1}}仅适用于第一个操作数的大小。

第3。其他评论:

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

在operator +()中,初始化temp而不访问其内部结构是一个好习惯:nullptr将更易维护且不易出错。

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

最后一句话:你有没有想过你班级的用户可以做一些奇怪的事情,例如:main()不是你的算子+然后尝试访问空指针?

答案 2 :(得分:2)

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

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

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