Зачем нужен деструктор?
#новичкам
На самом деле даже разработчики с опытом не всегда правильно отвечают на вопрос. Потому что все эти конструкторы и деструкторы крутятся вокруг ресурсов. Но вот каких именно? Давайте разбираться.
Несколько раз слышал ответ: "освобождает память, занятую объектом".
Следом идет вопрос: - "То есть деструктор деаллоцирует память, на месте которой находится объект?". После положительного ответа я привожу пару примеров:
void foo() {
std::vector vec = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
std::cout ~ArrType();
}
Происходит ли деаллокация динамической памяти в этом случае? Что здесь делает деструктор?
На самом деле деструктор просто семантически разрушает объект. Собственно это и есть значение слова "destructor" - разрушитель.
На такие темы надо рассуждать с точки зрения лайфтайма объекта. Конструктор создает объект и начинает его время жизни(даже если он ничего не делает). Деструктор же разрушает объект и заканчивает его время жизни.
Заметьте, пока про ресурсы ни слова.
Будут ли хоть какие-то ресурсы у объекта такого класса?
struct A {
int i;
char c;
};
Нет. Хотя у него есть конструктор и деструктор. Да, тривиальные, но есть же.
Когда я делаю:
void foo() {
A obj;
}
foo();
Вызывается и конструктор, и деструктор(при выходе из скоупа функции). Аллокацию и деаллокацию памяти под obj выполняет сам код, обеспечивающий запуск функции.
Разговор о ресурсах начинается тогда, когда в логике объекта заложено обладание ими. std::vector владеет указателем на динамическую память и за счет этого может масштабировать количество элементов в рантайме.
Какой-нибудь коннекшен к базе владеет открытым сокетом, через который он может общаться с ней.
Только тогда, когда объект действительно единолично владеет каким-то ресурсом, при разрушении объекта нужно этот ресурс освободить. И это не всегда память! Файловые дескрипторы и потоки - это тоже ресурсы и будет плохо, если их не освобождать.
Вернемся к примерам из начала поста.
void foo() {
using ArrType = std::array; // just for explicit destructor call
auto * ptr = new ArrType{0, 1, 2, 3, 4};
ptr->~ArrType();
}
std::array - это тонкая обертка над сишным массивом. Для его работы не нужны дополнительные ресурсы: его элементы располагаются ровно там, где аллоцировали память под сам объект. Поэтому и деструктор у него ничего не делает.
В примере вообще нет деаллокаций динамической памяти, так как в нем отсутствует delete, который и занимается деаллокациями.
Теперь другой:
void foo() {
std::vector vec = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
std::cout
#новичкам
На самом деле даже разработчики с опытом не всегда правильно отвечают на вопрос. Потому что все эти конструкторы и деструкторы крутятся вокруг ресурсов. Но вот каких именно? Давайте разбираться.
Несколько раз слышал ответ: "освобождает память, занятую объектом".
Следом идет вопрос: - "То есть деструктор деаллоцирует память, на месте которой находится объект?". После положительного ответа я привожу пару примеров:
void foo() {
std::vector vec = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
std::cout ~ArrType();
}
Происходит ли деаллокация динамической памяти в этом случае? Что здесь делает деструктор?
На самом деле деструктор просто семантически разрушает объект. Собственно это и есть значение слова "destructor" - разрушитель.
На такие темы надо рассуждать с точки зрения лайфтайма объекта. Конструктор создает объект и начинает его время жизни(даже если он ничего не делает). Деструктор же разрушает объект и заканчивает его время жизни.
Заметьте, пока про ресурсы ни слова.
Будут ли хоть какие-то ресурсы у объекта такого класса?
struct A {
int i;
char c;
};
Нет. Хотя у него есть конструктор и деструктор. Да, тривиальные, но есть же.
Когда я делаю:
void foo() {
A obj;
}
foo();
Вызывается и конструктор, и деструктор(при выходе из скоупа функции). Аллокацию и деаллокацию памяти под obj выполняет сам код, обеспечивающий запуск функции.
Разговор о ресурсах начинается тогда, когда в логике объекта заложено обладание ими. std::vector владеет указателем на динамическую память и за счет этого может масштабировать количество элементов в рантайме.
Какой-нибудь коннекшен к базе владеет открытым сокетом, через который он может общаться с ней.
Только тогда, когда объект действительно единолично владеет каким-то ресурсом, при разрушении объекта нужно этот ресурс освободить. И это не всегда память! Файловые дескрипторы и потоки - это тоже ресурсы и будет плохо, если их не освобождать.
Вернемся к примерам из начала поста.
void foo() {
using ArrType = std::array; // just for explicit destructor call
auto * ptr = new ArrType{0, 1, 2, 3, 4};
ptr->~ArrType();
}
std::array - это тонкая обертка над сишным массивом. Для его работы не нужны дополнительные ресурсы: его элементы располагаются ровно там, где аллоцировали память под сам объект. Поэтому и деструктор у него ничего не делает.
В примере вообще нет деаллокаций динамической памяти, так как в нем отсутствует delete, который и занимается деаллокациями.
Теперь другой:
void foo() {
std::vector vec = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
std::cout