为什么此代码不会导致内存泄漏

Why does this code not result in a memory leak?

本文关键字:内存 泄漏 代码 为什么      更新时间:2023-10-16

我用--leak-check=full valgrind C++检查了以下代码,它说没有内存泄漏。为什么?

char *p = new char[256];
delete p;

据我所知,new[]应该与delete[]相匹配。

尽管正如@KillianDS所说,这是未定义的行为,但差异可能与deletedelete[]释放底层内存的事实有关。delete[]的要点是在释放内存之前调用数组中每个对象的析构函数。由于char是一个 POD,并且没有析构函数,因此在这种情况下,两者之间没有任何有效的区别。

但是,您绝对不应该依赖它。

只有当

p指向基本数据类型(如 char 或 int)时,deletedelete[] 才会相等。

如果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确实注意到了这个问题。

因为它是未定义的行为。在您的情况下,delete可能会在编译器中执行delete []工作,但它可能无法在另一台计算机上工作。

这是未定义的行为,因此我们无法推理其行为。如果我们看一下C++草案3.7.4.2分配函数的标准部分,第3段说(强调我的):

[...]否则,如果提供给标准库中运算符 delete(void*) 的值不是以前调用标准库中运算符 new(std::size_t) 或运算符 new(std::size_t, constd::nothrow_t&) 返回的值之一,则行为未定义;如果提供给标准库中运算符 delete[] (void*) 的值不是以前调用的运算符 new[] (std::size_t) 或运算符 new[] (std::size_t, const std::nothrow_t&) 标准库。

实际细节将是实现定义的行为,并且可能会有很大差异。

deletedelete [] 之间的区别在于编译器添加代码来调用删除对象的析构函数。像这样说:

    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;

哪个实习生调用free()来释放内存。这就是您没有泄漏的原因。由于分配的内存是使用 g++ 中的 free() 完全释放的。

但最佳做法是,如果您使用delete []版本,则必须使用new []