Завершено
2
16.11.2020, 15:53
01.12.2020, 09:34
Реализовать обнаружение утечек памяти с C++ программах.
Простейший способ обнаружения утечки памяти с помощью функции _DumpMemoryLeaks
в Visual Studio.
// main.cpp
void main(void) {
// код
_CrtDumpMemoryLeaks(); // здесь вся выделенная память должна быть освобождена
}
Но данный способ не работает, если существуют сложные глобальные и статические объекты.
// main.cpp
class A {
char * p;
public:
A(void) : p(new char[1024]) {}
~A(void) { delete[] p; }
};
static A staticA;
void fn(void) {
static A localstaticA;
}
void main(void) {
fn();
_CrtDumpMemoryLeaks(); // глобальные объекты не уничтожены, их деструкторы не вызваны
}
Кроме того, глобальные статические объекты могут быть объявлены и созданы в другом модуле.
// another.cpp
class B {
char * p;
public:
B(void) : p(new char[256]) {}
~B(void) { delete[] p; }
};
static B staticB;
void g(void) {
static B localstaticB;
}
Первое приближение
Чтобы корректно детектировать утечки памяти, необходимо создать глобальный объект, который в деструкторе будет вызывать _CrtDumpMemoryLeaks()
.
class MemoryDump {
public:
MemoryDump(void) { }
~MemoryDump(void) { _CrtDumpMemoryLeaks(); }
};
Объект класса MemoryDump
должен быть создан в самом начале cpp файла, так чтобы он, среди других глобальных и статических объектов всегда создавался первым. Тогда при деинициализации гарантируется обратный порядок вызова деструкторов, и поэтому _CrtDumpMemoryLeaks()
в деструкторе будет вызвана уже после вызова деструкторов у всех остальных глобальных объектов.
Второе приближение
Если в проекте присутствует несколько cpp файлов, то потребуется создать несколько таких глобальных объектов (т.к. порядок инициализации / деинициализации глобальных объектов в разных модулях не определён и может быть любым). Но при этом требуется чтобы _CrtDumpMemoryLeaks()
вызывалась только в последнем вызове деструктора.
Для этого потребуется преобразовать наш класс в соответствии с паттерном одиночка: создание и уничтожение объекта происходит множество раз, но реально существует всегда только один экземпляр объекта, который один раз создаётся (первый вызов конструктора) и только один раз уничтожается (последний вызов деструктора).
Результат
Необходимо оформить класс и всю необходимую логику в виде отдельного модуля, а также сформулировать дополнительные правила использования этого модуля (если требуется).
Приведённый выше код можно использовать в качестве тестовых примеров для проверки работы модуля.