1. Можно ли удалять объекты из стека? (также как удаление объектов из кучи)
Память в стеке выделяется не так, как в куче, не произвольно, а последовательно. Когда в стеке выделили память для объектов
a и
b, то указатель стека указывает на
b или свободное место за ним, и память объекта
a использовать уже нельзя, даже если она уже не нужна: объект
b неперемещаемый (вообще все объекты в памяти неперемещаемые, это нужно для того, чтобы работали указатели). Только когда память объекта
b будет освобождена - стек уменьшится - тогда можно будет освободить и память объекта
a. Стек напрямую программисту неподконтролен, а управляется языком:
1. При входе в блок (в Си) или при объявлении объекта (в C++) стек увеличивается, и в нём размещается этот объект.
1'. При выходе из блока объект уничтожается (если несколько объектов, то в порядке, обратном порядку создания), после чего стек уменьшается.
2. При вычислении выражений, если требуется сохранить временный результат вычислений, создаётся временный объект, аналогично.
2'. При окончании вычисления выражения этот объект уничтожается.
3. При вызове функции, в стеке размещаются все параметры функции (указатели для параметров, переданных по ссылке, дополнительно указатель
this для методов объектов), место для возвращаемого значения, служебная информация (например, адрес возврата), и потом управление передаётся функции. Функция размещает свои локальные переменные как объекты в блоке, по п. 1.
3'. При возврате из функции, возвращаемое значение конструируется из выражения в
return, потом управление возвращается в вызывающую функцию, и там вся информация (параметры, возвращаемое значение) уничтожается как временные объекты.
4. При выбросе исключения происходит несколько последовательных возвратов из функций, как в п. 3'. Сам объект-исключение при этом находится не в стеке, а то бы стек нельзя было освободить.
2. Что происходит при вызове деструктора для объекта в стеке
Ничего хорошего, потому что полностью это выглядит так:
{ // начало блока
MyClass a = MyClass(); // объявление, выделение памяти в стеке, вызов конструктора для объекта
// (или даже двух конструкторов - для временного объекта, и копирующего)
a.~MyClass(); // вызов деструктора для объекта
} // конец блока, язык пытается вызвать деструктор для объекта a перед освобождением памяти
// второй вызов деструктора для невалидного объекта может привести к катастрофе
3.Delete, насколько я понимаю, возвращает память операционной системе, и мы не должны иметь ней доступ из программы, тогда что мы получает по указателю после delete?
Указатель на свободную память. Обычно там записаны служебные значения исполняющей системы, и если туда чего-нибудь записать своё, то можно испортить кучу программы, и грохнуть её. Вот операционную систему (в хороших ОС) так грохнуть не получится.
Хорошим тоном является записывать 0 в указатель, который освободили.