7

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 ?

Eli
  • 6,353
  • 9
  • 30
  • 25
  • Duplicate? http://stackoverflow.com/questions/1913343/how-could-pairing-new-with-delete-possibly-lead-to-memory-leak-only – Philip Potter Mar 09 '10 at 09:10
  • @Philip Potter: Not of that very question - that one is specifically about causing a memory leak. And memory leak is not typical in this case. – sharptooth Mar 09 '10 at 09:15
  • Try it with an array of `shared_ptr`, each pointing to a different allocated int, and you'll see whether your implementation is making `delete` and `delete[]` equivalent. Always this fascination in C++ with things that people know are wrong, are clearly stated in the standard to be wrong, and yet which appear as if they might sometimes just happen to work ;-) – Steve Jessop Mar 09 '10 at 09:43
  • @Steve Jessop: unfurtunalty it makes people seems stupid when they use the argument: "its undefined in the standard and therefore should not be used". MS habit of relaxing the rules when implementing standard leads developers to feel a false sense of security when writing none complaint code/ – Eli Mar 09 '10 at 11:35
  • That thing you quoted is stupid if the code is intended for MSVC only. But the correct rule is "it's undefined in the standard and therefore should not be used *unless Microsoft defines the behavior* ". The false-sense-of-security developer is using the rule "it's undefined in the standard and therefore can be used as long as it doesn't crash/leak/fail when I run it". This just isn't good enough for C++ - even with a good set of unit tests you're just saving up trouble if you rely on undefined behavior. A small change in future can change the behavior and trigger a lot of rewriting. – Steve Jessop Mar 09 '10 at 11:40
  • 1
    Not to mention that no developer on earth can justify the claim, "ah, yes, I fully understand the difference between `delete` and `delete[]`, but for arrays of POD type in MSVC-only code, I cleverly use `delete` on purpose, as an optimization to save typing two extra characters". No you don't, you just forgot. Admit the error, correct it, and stop wasting time arguing ;-) – Steve Jessop Mar 09 '10 at 11:46
  • @Steve Jessop: I am going to copy your last comment to a power-point slide to be used when appropriate ;-)) – Eli Mar 09 '10 at 11:57

8 Answers8

19

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
  • 34,244
  • 12
  • 79
  • 148
17

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.

Community
  • 1
  • 1
sharptooth
  • 167,383
  • 100
  • 513
  • 979
3

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
  • 12,825
  • 5
  • 58
  • 90
3

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.

2

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

knittl
  • 246,190
  • 53
  • 318
  • 364
2

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
  • 54,544
  • 15
  • 116
  • 120
1

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,807
  • 13
  • 26
1

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
  • 4,791
  • 3
  • 24
  • 32