#c #memory-leaks #destructor #delete-operator
#c #утечки памяти #деструктор #оператор удаления
Вопрос:
Относительно простой вопрос о правильной обработке деструкторов…
Сначала у меня есть класс, который выглядит примерно так:
class Foo {
public:
ReleaseObjects() {
for (std::map<size_t, Object*>::iterator iter = objects.begin(); iter != objects.end(); iter ) {
delete (*iter).second;
}
objects.clear();
}
private:
std::map<size_t,Object*> objects;
}
Таким образом, функция просто удаляет объекты, которые были созданы с использованием ‘new’. Проблема заключается в классе объекта:
class Bar : public Object {
public:
Bar() {
baz = new Baz();
}
~Bar() { delete baz; }
private:
Baz* baz;
}
Если я добавляю объект типа Baz в Foo, а затем пытаюсь ReleaseObjects() , я получаю утечку памяти (valgrind). Проблема указывает на утечку baz, и я предполагаю, что это означает, что деструктор в bar никогда не вызывается? Итак, что я хотел бы знать, так это как вызвать деструктор Bar при попытке уничтожить этот объект (я не могу изменить класс Bar, но я могу изменить Foo).
Редактировать: Упс, извините за синтаксические ошибки. В любом случае, спасибо за все ответы, глупый я забыл реализовать правильный деструктор в моем классе Baz! О, и Baz на самом деле является шаблонным классом, но я подумал, что Baz не имеет отношения к моему вопросу, и проблема заключалась в том, что деструктор в Bar не вызывался… ну, я был неправ, проблема все-таки в базе. Но еще раз спасибо, я думаю, что я понял это отсюда!
Комментарии:
1. Является ли деструктор в объекте виртуальным? Также опубликуйте класс объекта
2. Этот код не протекал. Этот код даже не компилировался. Пожалуйста, опубликуйте фактический код.
3. Можете ли вы опубликовать класс (или что бы это ни было) для Baz?
4. Пожалуйста, опубликуйте минимальную, полную программу, которая демонстрирует ошибку. См . sscce.org для получения дополнительной информации.
5. Какую конкретную ошибку вы получаете? И вы добавляете Baz в Foo или Bar на карту Foo? «Delete (* iter).second должен правильно запускать деструктор Bar.
Ответ №1:
Вы должны убедиться, что ваш деструктор является виртуальным, чтобы вызывался соответствующий производный деструктор.
class Object {
. . .
virtual ~Object()
. . .
};
Комментарии:
1. Это в значительной степени то, что я забыл реализовать! И я думал, что моя проблема заключается в чем-то совершенно другом… Спасибо!
Ответ №2:
Я не совсем понимаю ваш сценарий, но поскольку у вас есть общедоступное наследование, вам, вероятно, нужны виртуальные деструкторы. В частности, базовому классу (объекту) нужен виртуальный деструктор.
Обратите внимание, что ваш данный код не может скомпилироваться. Оператор new возвращает указатель, поэтому baz
должен быть указатель.
Ответ №3:
Вы всегда должны всегда использовать интеллектуальные указатели. Эти типы ведут себя как указатели, но автоматически освобождают память и устраняют необходимость в любых таких функциях. Они избегают всевозможных неприятных ошибок — потенциально включая эту, если вы использовали a shared_ptr<Bar>
и удалили ее.
Если вы хотите написать нетривиальное программное обеспечение на C , вы должны знать и понимать интеллектуальные указатели.
Комментарии:
1. Если проблема заключается в невиртуальном деструкторе, я не думаю, что shared_ptr будет работать. (Хотя и не уверен на 100%)
2. @MooingDuck: он использует стирание типов для деструктора и, следовательно, позволит избежать этой проблемы, если вы начали с
Bar
.