【问题标题】:Error when calling destructor调用析构函数时出错
【发布时间】:2014-11-30 21:39:09
【问题描述】:

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

#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++;

    }

}

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

【问题讨论】:

    标签: c++


    【解决方案1】:

    你也应该实现copy constructorassignment operator

    【讨论】:

      【解决方案2】:

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

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

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

      【讨论】:

        【解决方案3】:

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

        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 在 operator+() 末尾已被删除!因此 Z 将引用一个悬空指针,造成很多伤害,尤其是在离开 main() 时,Z 的析构函数会尝试 dto 再次删除它!

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

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

        顺便说一句,即使它不是这里问题的直接原因,您也可以通过添加两个操作数的大小来初始化 temp 大小 a,但您分配 b 仅用于第一个操作数的大小。

        3.其他备注:

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

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

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

        最后一句话:你有没有想过你班级的用户会做一些奇怪的事情,例如:Overload E, G(0), H(1); E = H+G; 你的 operator+ 不会尝试访问空指针吗?

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-11-25
          • 2014-07-15
          • 2012-04-15
          • 2013-07-13
          • 2013-01-01
          • 1970-01-01
          • 2011-04-16
          相关资源
          最近更新 更多