Временный объект не уничтожен правильно?
Смотрите этот код здесь:
class test
{
int n;
int *j;
public:
test(int m)
{
n = 12;
j = new int;
cin >> *j;
}
void show()
{
cout << n << ' ' << *j << endl;
}
~test()
{
delete j;
}
};
int main()
{
test var = 123;
var.show();
return 0;
}
В этой программе компилятор должен пожаловаться на двойное удаление j
, Первое удаление выполняется, когда временный объект temporary(123)
уничтожен Второе удаление выполняется, когда var
Объект уничтожен. Но это работает нормально?
Значит ли это, что временный объект не вызывает деструктор?
3 ответа
Спорная линия такова:
test var = 123;
Полагаю, что соответствующий стандартный текст (на который ссылаются эксперты в комментариях) (8.5, "Заявители"):
Выбранная функция вызывается с выражением инициализатора в качестве аргумента; если функция является конструктором, то вызов инициализирует временную версию cv-unqualed-определенной версии целевого типа. Временное значение. Результат вызова (который является временным для случая конструктора) затем используется для прямой инициализации, в соответствии с приведенными выше правилами, объекта, который является местом назначения инициализации копирования. В некоторых случаях реализация позволяет исключить копирование, присущее этой прямой инициализации, путем создания промежуточного результата непосредственно в инициализируемом объекте;
Действительно, в 12.6 мы получаем пример этого:
complex f = 3; // construct complex(3) using
// complex(double)
// copy it into f
Таким образом, в вашем использовании =
Ваша реализация, вероятно, напрямую создает объект и полностью исключает промежуточный временный объект (и, как отмечалось в комментариях, большинство это делает).
Этот класс не копирует должным образом, поэтому создание его копии (и освобождение копии и оригинала) приведет к двойному удалению (и сбоям, неопределенному поведению и т. Д.). Поскольку копии не создаются, этот сценарий не происходит выше.
Два момента: во-первых, в данном конкретном случае компилятору разрешено оптимизировать временное с помощью явного разрешения стандарта. Все компиляторы, с которыми я знаком, делают. Вы можете проверить, происходит ли это в вашем коде, определив конструктор копирования и применив его.
Во-вторых, если временное не оптимизировано, ваш код имеет неопределенное поведение. Двойное удаление может иметь любое мыслимое поведение: немедленный сбой, повреждение арены свободного пространства (приводящее к гораздо более позднему сбоям, если программа продолжит работать), никакого эффекта, как никогда, или что-либо еще. Тот факт, что вы не видите никаких симптомов, не означает, что код правильный.
Тот факт, что код не взорвался, не означает, что он правильный.
Ваш класс глючит в том, что он подвержен удвоению deletes
так, как вы описываете.
Например, изменение var.show();
к следующему:
test(var).show();
делает код надежно взорван на моем компьютере.
Чтобы исправить, реализуйте конструктор копирования и оператор присваивания.