Вызов деструктора для скалярных типов и неопределенного поведения

Я только что написал следующую программу, и она компилируется и работает нормально. (см. живую демонстрацию здесь)

#include <iostream>
typedef int T;
int main()
{
    int a=3;
    std::cout<<a<<'\n';
    a.~T();
    std::cout<<a;
    return 0;
}

Почему программа компилируется нормально? Если я не ошибаюсь, у скалярных типов нет конструктора и деструктора в C++. Итак, хорошо ли определена эта программа? Уничтожает ли в этом случае явный вызов деструктора variable a или он будет автоматически уничтожен компилятором по завершении выполнения функции? Я знаю, что доступ к объекту после окончания его жизни имеет неопределенное поведение в C++. Но что об этом говорит стандарт C++?

Я нашел немного похожий вопрос здесь на SO . Ответ, данный @Columbo, говорит, что:

Вы не можете вызвать деструктор для скалярных типов, потому что у них его нет. Этот оператор разрешен исключительно для кода шаблона, в котором вы вызываете деструктор объекта, тип которого вам неизвестен, — он устраняет необходимость написания специализации для скалярных (или даже массивных) типов.

Поэтому я не понимаю объяснения, данного им. Было бы лучше, если бы кто-то объяснил это с помощью шаблонного кода, в котором вызывается деструктор объекта, тип которого неизвестен. Буду признателен, если кто-нибудь объяснит это на простом примере.


person Destructor    schedule 26.08.2015    source источник
comment
@vsoftco: почему до сих пор никто не дал ответа? ТАК быстро, когда каждый раз я публикую любой вопрос, но на этот раз выглядит так медленно.   -  person Destructor    schedule 26.08.2015
comment
Я связался с точно таким же вопросом, заданным в другом месте - хотя на этот вопрос еще нет полного ответа, он будет затронут ссылкой   -  person M.M    schedule 26.08.2015
comment
@vsoftco хорошо, стираю   -  person M.M    schedule 26.08.2015
comment
Кто-нибудь может прокомментировать, легальна ли программа? Можем ли мы явно вызвать (тривиальный) деструктор фундаментального типа (даже если мы вызываем его через typedef)? И g++, и clang++ не жалуются...   -  person vsoftco    schedule 26.08.2015
comment
@vsoftco Это законно, и в связанном ответе Коломбо говорится, почему ... когда вы делаете вызов псевдодеструктора, как в приведенном выше примере, единственное, что происходит, - это оценивается выражение слева от точки. IOW, сам вызов деструктора является NOP.   -  person Praetorian    schedule 26.08.2015


Ответы (1)


Согласно этому:

Тривиальный деструктор — это деструктор, который не выполняет никаких действий. Объекты с тривиальными деструкторами не требуют выражения удаления, и от них можно избавиться, просто освободив их память. Все типы данных, совместимые с языком C (типы POD), легко уничтожаются.

Вероятно, это похоже на то, что в C++ вы можете инициализировать любой объект типа POD, как любой объект типа класса, вызвав его конструктор с (init_val), например int i(-1);

Но обратите внимание, что по определению вызов деструктора непосредственно для обычного объекта, такого как локальная переменная, приводит к неопределенному поведению при повторном вызове деструктора в конце области видимости.

person Alex Lop.    schedule 26.08.2015
comment
Отсутствие действий на самом деле означает то, что он говорит. Тривиальный деструктор может вызываться несколько раз или вообще не вызываться, и это не имеет значения. (Без УБ.) - person Potatoswatter; 26.08.2015
comment
@Potatoswatter определение тривиального деструктора в 12.4 предполагает, что только типы классов могут иметь деструктор (не говоря уже о тривиальном деструкторе, который является не объявленным пользователем деструктором класса, отвечающим определенным требованиям) - person M.M; 26.08.2015
comment
@АлексЛоп. ваш ответ, кажется, противоречит сам себе, вы говорите, что код OP вызывает неопределенное поведение или нет? - person M.M; 26.08.2015
comment
@MattMcNabb Честная ерунда, но вызов псевдодеструктора имеет ту же семантику, что и тривиальный деструктор. - person Potatoswatter; 26.08.2015
comment
@Potatoswatter Итак, вы говорите, что код OP здесь вызывает UB, обращаясь к a после окончания его времени жизни (поскольку тривиальные деструкторы заканчивают время жизни своего объекта, и вы говорите, что вызов псевдодеструктора имеет ту же семантику). Однако ответ Коломбо в дублирующемся потоке, похоже, говорит, что он не вызывает UB, потому что псевдодеструктор не имеет никакого эффекта, хотя он не совсем ясно об этом. - person M.M; 26.08.2015
comment
@Potatoswatter, Мэтт Макнабб: все еще не отвечает на мой вопрос. Было бы лучше, если бы вы написали ответ, который объясняет это, используя код шаблона, в котором вызывается деструктор объекта, тип которого неизвестен. - person Destructor; 26.08.2015
comment
@MattMcNabb [basic.life]/1 утверждает, что время жизни объекта типа класса с нетривиальным деструктором заканчивается, когда начинается вызов деструктора, поэтому пример в OP не заканчивается время жизни int. И это восходит к тому, что утверждает Коломбо, скалярные типы не имеют деструкторов, а вызов псевдодеструктора ничего не делает. - person Praetorian; 26.08.2015
comment
@PravasiMeet см. ответ Коломбо. Его ответ можно было бы немного уточнить, но мне нечего добавить к нему. - person M.M; 26.08.2015
comment
@MattMcNabb Я говорю, что явный вызов диструктора обычного объекта имеет неопределенное поведение. В случае типов POD это, вероятно, ничего не делает, но я не смог найти ничего официального с таким заявлением. - person Alex Lop.; 26.08.2015
comment
@АлексЛоп. объекты типа POD или int являются объектами, я не уверен, какое различие вы проводите со словом обычный - person M.M; 26.08.2015
comment
@MattMcNabb Нет, я сказал, что тривиальный деструктор не имеет никакого эффекта. На этом не заканчивается жизнь чего бы то ни было. Также не вызывает псевдодеструктор. УБ нет. - person Potatoswatter; 26.08.2015
comment
@Potatoswatter Я бы посчитал, что окончание жизни и не окончание жизни - это разные семантики! - person M.M; 26.08.2015
comment
@MattMcNabb Я никогда ничего не говорил о конце жизни. Все мои комментарии однозначно говорят о том, что эти конструкции абсолютно ничего не делают. О чем ты говоришь? - person Potatoswatter; 26.08.2015
comment
… Возможно, вам следует задать вопрос с вашей заботой. Я думаю, у вас сложилось впечатление, что деструктор тривиально разрушаемого класса имеет какое-то тонкое значение. Это не так. - person Potatoswatter; 26.08.2015
comment
@Potatoswatter Хорошо, теперь я вижу, что время жизни объектов типа класса, имеющих тривиальный деструктор, не заканчивается вызовом их деструктора. Итак, struct A { int x; } a; a.~A(); a.~A(); является законным. - person M.M; 26.08.2015