29

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

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

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

4

6 回答 6

38

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

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

于 2013-09-27T07:15:51.383 回答
12

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]' 的析构函数将被调用。

于 2013-09-27T07:20:43.317 回答
11

当我尝试这个时,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 确实注意到了这个问题。

于 2013-09-27T07:36:55.123 回答
7

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

于 2013-09-27T07:14:45.333 回答
1

这是未定义的行为,因此我们无法推断其行为。如果我们查看草案 C++ 标准部分3.7.4.2 Deallocation functions,第3段说(强调我的):

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

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

于 2013-09-27T09:37:33.047 回答
0

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;

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

但最佳做法是,delete []如果您使用new [].

于 2013-09-27T07:59:58.220 回答