Вопрос по c++ – Valgrind не сообщает об утечке памяти при «удалении массива»

0

После реализации кода C ++, приведенного ниже, я запустилvalgrind --leak-check=full чтобы проверить, не было ли утечки памяти. Результат был 0 байт были использованы на выходе а также утечки не возможны.

Однако позже я обнаружил, что забыл использоватьdelete[] x вместо простоdelete x внутри деструктора.

Я искал некоторые объяснения (например:ператоры @delete и delete [] в C ++) и все, что я прочитал, говорит, что используяdelete без[] может вызвать утечку памяти, поскольку вызывает только деструктор для первого объекта в массиве.

Я изменил код для удаления [], и вывод valgrind был таким же (как и ожидалось). Но теперь я в замешательстве: "Есть ли проблема с валгриндом или нет?&quodelete действительно отлично работает для массивов даже без оператора[]? "

#include <iostream>
#include <string.h>
using namespace std;
class Foo {
  private: char *x;
  public:
    Foo(const char* px) {
       this->x = new char[strlen(px)+1];
       strcpy(this->x, px);
    }
    ~Foo() {
       delete x;
    }
    void printInfo() {  cout << "x: " << x << endl;  }
};
int main() {
   Foo *objfoo = new Foo("ABC123");
   objfoo->printInfo();
   delete objfoo;
   return 0;
}
Спасибо Джерри, я не смог найти этот вопрос. Ответы там очень интересны Moacir Ponti
Ответы на вопрос, который вы связали, не содержат упоминаний об утечках памяти. На самом деле они говорят то же самое, что говорит Алс ниже. Так почему ты говоришь "все, что я прочитал, говорит, что использование delete без [] приводит к утечке памяти." ? Benjamin Lindley
Хотя вы обнаруживаете это с помощью другого инструмента, код и вопрос здесь являются возможной копиейункция @_CrtMemDumpAllObjectsSince () не может обнаружить утечки, если вызывается delete array вместо delete [] array и мой ответ на этот вопрос примерно одинаков. Jerry Coffin
Plus, используя valgrind 3.2.1 в вашей программе, отметьте, что существует 'Несоответствие free () / delete / delete []'. Это не утечка памяти, а ошибка. Dave S
Известно, что, например, MSVC генерирует один и тот же код дляdelete x а такжеdelete[] x когда массив содержит встроенные типы, такие какchar. Коддруго для типов классов с деструктором. Bo Persson

Ваш Ответ

2   ответа
7

Использование удаления без [] вызывает утечку памяти.

Нет, это вызывает Неопределенное поведение.

Ваша программа, в которой вы размещаете, используяnew [] и освободить с помощьюdelete имеет неопределенное поведение. На самом деле, вам повезло (довольно не повезло), это не демонстрирует странного поведения.

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

Upvote для "довольно неудачно". Sebastian Mach
Я бы не сказал этого лучше, но я процитирую FAQ, чтобы спрашивающий мог ссылаться на происходящее: «Ответственность за установление связи между новым T [n] и delete [] лежит на программисте, а не на компиляторе». p правильно. Если вы ошиблись, компилятор не сгенерирует ни сообщение об ошибке времени компиляции, ни времени выполнения. Повреждение кучи является вероятным результатом. Или хуже. Ваша программа, вероятно, умрет. " Parashift.com / C ++ - чаво-облегченный / FreeStore-mgmt.html # чаво-16,12 Stephen Newell
Стефен, да, я знаю, что это ответственность программиста, и я также знаю последствия. Я просто хочу понять, почему Valgrind не смог найти возможную утечку. Moacir Ponti
@ MoacirPontiJr .: Да. Неопределенное поведение означает, что все (в буквальном смысле) возможно. Как только программа имеет неопределенное поведение, вы не можете ожидать никакого поведения, все ставки отключены. Также, как я сказал в ответ на результат несоответствияnew [] а такжеdelete является неопределенным поведением, которое может быть не обязательно утечкой памяти. Alok Save
Алс, спасибо также за примечание. Означает ли неопределенное поведение, что никто не может знать, что произойдет? Но известно, что повреждение кучи очень вероятно (как цитирует Стивена), так почему валгринд не может его найти? Moacir Ponti
2

delete а такжеdelete[] не о освобождении памяти, а о вызовах деструкторов.

Пока официально неопределенное поведение, на практике это будет более или менее работать ... кроме этогоdelete вызовет только деструктор первого элемента.

Как примечание, вы можете получить проблему:

#include <iostream>

struct A{
  ~A() { std::cout << "destructor\n"; }
};

int main() {
  A* a = new A[10];
  delete a;
}

немного как

*** glibc detected *** ./prog: munmap_chunk(): invalid pointer: 0x093fe00c ***
======= Backtrace: =========
/lib/libc.so.6[0xb759dfd4]
/lib/libc.so.6[0xb759ef89]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/libstdc++.so.6(_ZdlPv+0x21)[0xb77602d1]
./prog(__gxx_personality_v0+0x18f)[0x8048763]
./prog(__gxx_personality_v0+0x4d)[0x8048621]
======= Memory map: ========

Посмотри на Ideone.

Я думаю, что это спор ОП с егоdelete вызов в деструкторе. Alok Save
Большинство реализаций (к счастью) потерпят неудачу для большинства типов, когда «удаляют новый T [n]», потому что они хранят размер перед выделением, таким образом, имея слегка смещенные указатели для вызова базового необработанного менеджера памяти PlasmaHH

Похожие вопросы