您好我正在学习运算符重载...我注意到程序在调用析构函数时崩溃..任何帮助表示赞赏。 感谢
#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)
答案 0 :(得分:4)
答案 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::vector
或std::unique_ptr
或标准提供的其他方法来处理这些事情。