Я проверил следующий код на С++ с valgrind
с --leak-check=full
, и он говорит, что утечка памяти отсутствует. Почему это?
char *p = new char[256];
delete p;
Насколько мне известно, new[]
должен соответствовать delete[]
.
Я проверил следующий код на С++ с valgrind
с --leak-check=full
, и он говорит, что утечка памяти отсутствует. Почему это?
char *p = new char[256];
delete p;
Насколько мне известно, new[]
должен соответствовать delete[]
.
Хотя поведение undefined как @KillianDS говорит, разница, вероятно, связана с тем, что обе delete
и delete[]
освобождают базовую память. Точка delete[]
заключается в том, что деструкторы для каждого объекта в массиве вызываются до освобождения памяти. Поскольку char
является POD и не имеет деструктора, в этом случае нет никакой эффективной разницы между ними.
Однако вы определенно не должны полагаться на это.
delete
и delete[]
будут равны, только если p
указывает на основные типы данных, такие как char или int.
Если p
указывает на массив объектов, результат будет другим. Попробуйте использовать код ниже:
class T {
public:
T() { cout << "constructor" << endl; }
~T() { cout << "destructor" << endl; }
};
int main()
{
const int NUM = 3;
T* p1 = new T[NUM];
cout << p1 << endl;
// delete[] p1;
delete p1;
T* p2 = new T[NUM];
cout << p2 << endl;
delete[] p2;
}
Используя delete[]
, будут задействованы все деструкторы T в массиве. С помощью delete
вызывается только p[0]
деструктор.
Когда я пытаюсь это сделать, valgrind сообщает:
==22707== Mismatched free() / delete / delete []
==22707== at 0x4C2B59C: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==22707== by 0x40066D: main (in /home/andrew/stackoverflow/memtest)
==22707== Address 0x5a1a040 is 0 bytes inside a block of size 256 alloc'd
==22707== at 0x4C2C037: operator new[](unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==22707== by 0x40065D: main (in /home/andrew/stackoverflow/memtest)
Это не утечка памяти, но valgrind замечает проблему.
Потому что это поведение undefined. В вашем случае delete
может выполнять работу delete []
в вашем компиляторе, но может не работать на другой машине.
Это undefined поведение, поэтому мы не можем рассуждать о его поведении. Если мы рассмотрим проект стандартного раздела С++ 3.7.4.2
Deallocation, в пункте 3 говорится (выделено мной):
[...] В противном случае поведение undefined, если значение, предоставленное оператору delete (void *) в стандартной библиотеке, не является одним из значений, возвращаемых предыдущим вызовом любого оператора new ( std:: size_t) или оператор new (std:: size_t, conststd:: nothrow_t &) в стандартной библиотеке, а поведение undefined, если значение, предоставленное оператору delete [] (void *) в стандартная библиотека не является одним из значений, возвращаемых предыдущим вызовом любого оператора new [] (std:: size_t) или оператора new [] (std:: size_t, const std:: nothrow_t &) в стандартная библиотека.
Фактические данные будут поведение, определяемое реализацией, и могут сильно различаться.
Разница между delete
и delete []
заключается в том, что компилятор добавляет код для вызова деструктора для удаления объектов. Скажите примерно так:
class A
{
int a;
public:
...
~A() { cout<<"D'tor"; }
};
a=new A[23];
delete [] a;
Этот delete [] a;
преобразуется в нечто вроде <
for (int i=0; i<23; i++)
{
a[i].A::~A();
}
std::delete a;
Итак, для вашего случая, так как это встроенный тип данных, деструктор для вызова не существует. Таким образом, он преобразуется как
std::delete a;
который intern вызывает free()
, чтобы освободить память. Это причина, по которой вы не получаете утечки. Поскольку выделенная память полностью освобождается, используя free()
в g++.
Но лучше всего использовать версию delete []
, если вы используете new []
.