Деструктор в контейнерах?

126
18 декабря 2020, 05:20

Допустим, есть класс:

class MyClass1
{
    int a;
    string s;
    ...
};
class MyClass2
{
    list<MyClass1> lst;
}

Как правильно для MyClass2 - объявить деструктор, который бы полностью уничтожал контейнер? Лично я пишу так:

~MyClass2()
{
    this->lst.clear();
    this->lst.shrink_to_fit();
}

Но this->lst.clear(); вызывает деструктор для каждого объекта контейнера, а - this->list.shrink_to_fit(); - "сжимает" размер буфера в соответствии с size. Но, например, когда size=0, capacity=1, т.е в любом случае, контейнер будет находиться в памяти, пусть даже и "условно" - не имея в себе элементов.

Вопрос: как полностью удалить контейнер из памяти?

Answer 1

Уже не первый раз замечаю подобные ситуации, когда в деструкторе какого-либо класса, содержащего контейнеры (типа std::vector, std::list и т.п.), управляющие временем жизни своих объектов зачем-то выполняют ручную очистку. В большинстве случаев это делать не нужно, когда умирает объект, содержащий контейнер, автоматически убивается и контейнер. В свою очередь деструктор контейнера вызывает деструкторы содержащихся на тот момент элементов контейнера и так по цепочке.

Таким образом, если элементы контейнера имеют (или не требуют вовсе) деструкторы, полностью уничтожающие себя, никакой ручной работы не требуется. Но если, скажем, по какой-то причине, вы храните в контейнере что-то типа сырых указателей, для которых ранее была выделена память, то, конечно, такие указатели нужно освободить (выполнить соответствующую форму delete) до того, как информация о них (адреса, по которым выделена память) будет уничтожена деструктором контейнера. В частности пройтись по ним соответствующим циклом. Но даже в таких случаях лучше положиться на подходящие умные указатели (например, std::unique_ptr или std::shared_ptr), чтобы избежать ненужной ручной работы по уничтожению (написанию деструктора).

Answer 2

После shrink_to_fit пустого контейнера capacity будет равно 0. А в деструкторе класса MyClass2 ничего писать не надо, так как деструктор списка сам все подчистит.

Answer 3

Если контейнер list хранит именно элементы MyClass1, а не указатели на них, то в деструкторе с этим контейнером ничего делать не надо, он сам всё почистит при разрушении объекта типа MyClass2.

Answer 4

Компилятор генерирует некоторое количество "умолчательного" кода для поддержки ООП. В том числе умолчательный деструктор, если вы не объявляете свой кастомный вариант. Умолчательный деструктор вызывает деструкторы всех экземплярных полей класса, т.е. в вашем случае и list.

А std::list, в свою очередь, достаточно умён, чтобы прибрать за собой, поэтому вашей задачей будет лишь реализация логики деструктора MyClass1, экземпляры которого хранятся в списке, если в этом есть необходимость (MyClass1 содержит неуправляемые ресурсы, требующие ручного освобождения).

READ ALSO
Вставка Watermark в поток печати

Вставка Watermark в поток печати

Microsoft говорит нам, что мы можем модифицировать поток печати посредством разработки плагинов для драйвера печати

106
Чтение бинарных данных из std::wifstream

Чтение бинарных данных из std::wifstream

Необходимо считать в std::string байты файлаОдно из требований: поддержка юникодных имен файлов

134
Примеры указателей в с++ [закрыт]

Примеры указателей в с++ [закрыт]

Хотите улучшить этот вопрос? Переформулируйте вопрос так, чтобы он был сосредоточен только на одной проблеме

92