Общие проблемы с динамической памятью:
- Динамическое выделение памяти с
new
и без освобождения с delete
.
- Динамическое выделение памяти с
new[]
и освобождение с delete
.
- Динамическое выделение памяти
new
и освобождение его с помощью free
.
- Динамическое выделение памяти
malloc
и освобождение его с помощью delete
.
В дополнение к утечкам памяти / повреждению памяти последние 3 сценария вызовут страшное неопределенное поведение .
Вот еще несколько возможных сценариев утечки памяти, которые я могу вспомнить:
- Если указателю, указывающему на динамически выделяемую область памяти, перед удалением будет присвоено новое значение, это приведет к висячему указателю и утечка памяти.
Пример кода:
char *a = new[128];
char *b = new[128];
b = a;
delete[]a;
delete[]b; // will not deallocate the pointer to the original allocated memory.
- указатели в контейнерах STL
Более распространенный и часто встречающийся сценарий - хранение указателей, указывающих на динамически размещенные типы в контейнерах STL. Важно отметить, что контейнеры STL берут на себя ответственность за удаление содержащегося объекта , только если это не указатель типа .
Нужно явно пройти через контейнер и удалить каждый содержащийся тип перед удалением самого контейнера. В противном случае возникает утечка памяти.
Здесь является примером такого сценария.
- Деструктор не виртуального базового класса
Удаление указателя на базовый класс, который указывает на любой динамически размещенный объект производного класса в куче. Это приводит к неопределенному поведению.
Пример кода:
class MyClass
{
public:
virtual void doSomething(){}
};
class MyClass2 : public MyClass
{
private:
std::string str;
public: MyClass2( std::string& s)
{
str=s;
}
virtual void doSomething(){}
};
int main()
{
std::str hello("hello");
MyClass * p = new MyClass2(hello);
if( p )
{
delete p;
}
return 0;
}
В этом примере вызывается только деструктор MyClass :: ~ MyClass (), а MyClass2 :: ~ MyClass2 () никогда не вызывается. Для соответствующего освобождения понадобится
MyClass::virtual ~MyClass(){}
- Вызов delete
по void
указателю
Пример кода:
void doSomething( void * p )
{
//do something interesting
if(p)
delete p;
}
int main()
{
A* p = new A();
doSomething(p);
return 0;
}
Вызов delete
по указателю void
, как в примере выше, приведет к утечке памяти и неопределенному поведению.