Почему утечка памяти в одном случае, а не в другом - PullRequest
0 голосов
/ 02 января 2019

Я создаю c++ объект двумя слегка отличающимися способами, в следующем коде, когда CASE равен 0, есть утечка памяти, но в случае else утечки нет.

#include <string>
#define CASE 1

class A {
private:
  std::string *s;
public:
  A(std::string *p_s) { s = p_s; }
};

int main() {
#if CASE==0
  auto a = A(new std::string("Hello"));
#else
  auto s = std::string("Hello");
  auto a = A(&s);
#endif
}

когда я устанавливаю CASE 0, valgrind говорит, что произошла утечка памяти

valgrind ./a.out 
==24351== Memcheck, a memory error detector
==24351== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==24351== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==24351== Command: ./a.out
==24351== 
==24351== 
==24351== HEAP SUMMARY:
==24351==     in use at exit: 32 bytes in 1 blocks
==24351==   total heap usage: 2 allocs, 1 frees, 72,736 bytes allocated
==24351== 
==24351== LEAK SUMMARY:
==24351==    definitely lost: 32 bytes in 1 blocks
==24351==    indirectly lost: 0 bytes in 0 blocks
==24351==      possibly lost: 0 bytes in 0 blocks
==24351==    still reachable: 0 bytes in 0 blocks
==24351==         suppressed: 0 bytes in 0 blocks
==24351== Rerun with --leak-check=full to see details of leaked memory
==24351== 
==24351== For counts of detected and suppressed errors, rerun with: -v
==24351== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

, в другом случае (т.е. define CASE 1) она работает как ожидалось, а valgrind - нетсообщить о любой утечке памяти.

Я не могу понять, в любом случае я передаю указатель, и я не освобождаю память в явном виде, тогда почему они ведут себя по-разному?

Ответы [ 4 ]

0 голосов
/ 02 января 2019

СЛУЧАЙ == 0

auto a = A(new std::string("Hello"));

Это означает, что вы new определяете объект в куче -> вам необходимо явно delete это - что вы не сделали во фрагменте -> утечки памяти.

еще

auto s = std::string("Hello");
auto a = A(&s);
  • auto s = std::string("Hello");: это означает, что вы создаете объект в стеке, и,
  • auto a = A(&s);: взять его адрес (конечно, в стеке).
  • Созданный объект будет автоматически удален, как только переменная выйдет из области видимости

-> утечки памяти нет.

0 голосов
/ 02 января 2019

Это ничем не отличается от:

// first case, leak
int *j = new int (5);
//
// second case, no leak
int q = 5;
int *j = &q;

В первом случае мы выделили память с new, и наша ответственность - delete, когда мы закончим.Во втором случае мы создаем q в стеке, и он уничтожается, когда выходит из области видимости.

0 голосов
/ 02 января 2019

Причина такого поведения заключается в том, что ваш класс A не предназначен для того, чтобы стать владельцем std::string*, переданного в него: его член std::string *s предполагает, что объект, указатель на который передается в конструктор, будет уничтожен внешне.

Это приводит к утечке памяти, когда объект не уничтожен: delete никогда не вызывается при new string, переданном в конструктор в первом случае, что вызывает утечку памяти.

Во втором случае указатель указывает на строку в автоматическом хранилище. По окончании main он уничтожается, предотвращая утечку памяти.

0 голосов
/ 02 января 2019

У вас нет утечки памяти, потому что у вас есть указатель.

У вас есть утечка памяти, потому что вы new что-то и не delete это.

Получение указателя на переменную автоматического хранения не останавливает автоматическую очистку переменной.

Фактически, попытка delete &a в этом случае была бы неправильной / сломанной / злой / недопустимой / ересью.

...