views:

272

answers:

8

following a discussion in a software meeting I've set out to find out if deleting a dynamically allocated, primitives array with plain delete will cause a memory leak.

I have written this tiny program and compiled it with visual studio 2008 running on windows XP:

#include "stdafx.h"
#include "Windows.h"

const unsigned long BLOCK_SIZE = 1024*100000;
int _tmain()
{
    for (unsigned int i =0; i < 1024*1000; i++)
    {
        int* p = new  int[1024*100000];
        for (int j =0;j<BLOCK_SIZE;j++) p[j]= j % 2;
        Sleep(1000);
        delete p;
    }
}

I than monitored the memory consumption of my application using task manager, surprisingly the memory was allocated and freed correctly, allocated memory did not steadily increase as was expected

I've modified my test program to allocate a non primitive type array :

#include "stdafx.h"
#include "Windows.h"


struct aStruct
{
    aStruct() : i(1), j(0) {}

    int i;
    char j;
} NonePrimitive;

const unsigned long BLOCK_SIZE = 1024*100000;
int _tmain()
{
    for (unsigned int i =0; i < 1024*100000; i++)
    {
        aStruct* p = new  aStruct[1024*100000];
        Sleep(1000);
        delete p;

    }
}

after running for for 10 minutes there was no meaningful increase in memory

I compiled the project with warning level 4 and got no warnings.

is it possible that the visual studio run time keep track of the allocated objects types so there is no different between delete and delete[] in that environment ?

+14  A: 

No, it's undefined behavior. Don't do it - use delete[].

In VC++ 7 to 9 it happens to work when the type in question has trivial destructor, but it might stop working on newer versions - usual stuff with undefined behavior. Don't do it anyway.

sharptooth
+2  A: 

no, you should use delete[] when dealing with arrays

knittl
+2  A: 

It's called undefined behaviour; it might work, but you don't know why, so you shouldn't stick with it.

I don't think Visual Studio keeps track of how you allocated the objects, as arrays or plain objects, and magically adds [] to your delete. It probably compiles delete p; to the same code as if you allocated with p = new int, and, as I said, for some reason it works. But you don't know why.

Viktor Sehr
+1  A: 

Just using delete won't call the destructors of the objects in the array. While it will possibly work as intended it is undefined as there are some differences in exactly how they work. So you shouldn't use it, even for built in types.

Yacoby
the FAQ has a very strong argument, thanks for pointing it out
Eli
+11  A: 

delete p, where p is an array is called undefined behaviour.

Specifically, when you allocate an array of raw data types (ints), the compiler doesnt have a lot of work to do, so it turns it into a simple malloc(), so delete p will probably work.

delete p is going to fail, typically, when:

  • p was a complex data type - delete p; won't know to call individual destructors.
  • a "user" overloads operator new[] and delete[] to use a different heap to the regular heap.
  • the debug runtime overloads operator new[] and delete[] to add extra tracking information for the array.
  • the compiler decides it needs to store extra RTTI information along with the object, which delete p; won't understand, but delete []p; will.
Chris Becke
+1  A: 

The reason seems not to leak memory is because delete is typically based on free, which already knows how much memory it needs to free. However, the c++ part is unlikely to be cleaned up correctly. I bet that only the destructor of the first object is called.

Jan
+1  A: 

Using delete with [] tells the compiler to call the destructor on every item of the array. Not using delete [] can cause memory leaks if used on an array of objects that use dynamic memory allocations like follows:

class AClass
{
public:
    AClass()
    {
        aString = new char[100];
    }
    ~AClass()
    {
        delete [] aString;
    }
private:
    const char *aString;
};

int main()
{
    AClass * p = new  AClass[1000];
    delete p; // wrong
    return 0;
}
sergiom
+3  A: 

One answer is that yes, it can cause memory leaks, because it doesn't call the destructor for every item in the array. That means that any additional memory owned by items in the array will leak.

The more standards-compliant answer is that it's undefined behaviour. The compiler, for example, has every right to use different memory pools for arrays than for non-array items. Doing the new one way but the delete the other could cause heap corruption.

Your compiler may make guarantees that the standard doesn't, but the first issue remains. For POD items that don't own additional memory (or resources like file handles) you might be OK.

Even if it's safe for your compiler and data items, don't do it anyway - it's also misleading to anyone trying to read your code.

Steve314