#include <iostream>
using namespace std;
class Exem {
int *a;
public:
Exem() { a = new int; *a = 0; };
Exem (int x) { a = new int; *a = x; };
~Exem () { delete a; };
int f (void);
Exem operator+ (Exem);
};
int Exem::f (void) {
return *a * 2;
}
Exem Exem::operator+ (Exem nimda) {
Exem aux;
*aux.a = *a + *nimda.a;
return aux;
}
int main() {
Exem adabo(1);
Exem inakos(2);
adabo = adabo + inakos;
cout << adabo.f();
cin.get();
}
这是我的代码,用于展示问题的示例类。理论上,main()的输出为'6',但实际显示的只是无意义的数字。
这显然与类的析构函数有关,根据我的理解,它在操作符+函数结束时被过早调用 - 在实际传递之前,aux会丢失。我得出了这样的结论,因为~exm()在被注释时允许程序按预期执行。
我猜这与这两个编译器有关,因为当我尝试在Embarcadero RAD Studio中编译完全相同的代码时,它会起作用。
答案 0 :(得分:2)
您需要为Exem
显式定义复制构造函数和赋值运算符,因为您有一个动态分配的成员变量。
如果没有为类显式定义复制构造函数和赋值运算符,则编译器会生成这些的默认版本,这些版本不适用于具有动态分配成员的类。默认生成的版本不适合的原因是它们执行成员的浅表副本。在Exem
的情况下,当复制它的实例时,Exem
的多个实例指向名为int
的同一动态分配的a
成员。当其中一个实例被销毁时a
delete
d,并使另一个实例留下悬空指针和未定义的行为。
请参阅rule of three。
Exem
的简单修正方法是a
从int*
更改为int
。默认的复制构造函数,赋值运算符和析构函数都是正确的。
请注意,Exem::operator+()
应采用const Exem&
参数,因为它不会更改其参数。