#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», но все, что на самом деле появляется, это бессмысленные числа.
По-видимому, это связано с деструктором класса, который, как я понял, вызывается слишком рано в конце функции operator + — aux теряется до того, как его фактически пропустят. Я пришел к такому выводу, потому что ~ Exem (), когда он прокомментирован, позволяет программе работать так, как ожидалось.
Я предполагаю, что это связано с этими двумя компиляторами, потому что, когда я попытался скомпилировать точно такой же код в Embarcadero RAD Studio, это сработало бы.
Вам нужно явно определить конструктор копирования и оператор присваивания для Exem
так как у вас есть динамически распределяемая переменная-член.
Если конструктор копирования и оператор присваивания не определены явно для класса, компилятор генерирует их версии по умолчанию, которые не подходят для класса, который имеет динамически размещаемые члены. Причиной того, что созданные по умолчанию версии являются неподходящими, является то, что они выполняют поверхностную копию элементов. В случае Exem
когда экземпляр этого копируется более чем один экземпляр Exem
указывает на тот же динамически распределяемый int
член по имени a
, Когда один из экземпляров уничтожен, a
delete
d и оставляет другой экземпляр с висящим указателем и неопределенным поведением.
Увидеть правило трех.
Простое исправление для Exem
будет меняться a
из int*
для int
, Конструктор копирования по умолчанию, оператор присваивания и деструктор будут правильными.
Обратите внимание, что Exem::operator+()
должен взять const Exem&
параметр, поскольку он не меняет свой аргумент.
Других решений пока нет …