1

The title is the question.

I still don't quite understand the behavior of dynamically allocated storages.

#include <utility>
int main() {
    // Case 1:
    volatile char *c1 = new char; // I'm gonna make these volatile, so the compiler won't change the code.
    volatile char *d1 = c1;
    delete d1;
    // Case 2:
    volatile char *c2 = new char[4];
    volatile char *d2 = c2;
    delete []d2;
    // Case 3:
    volatile char *c3 = new char;
    volatile char *d3 = std::move(c3);
    delete d3;
    // Case 4:
    volatile char *c4 = new char[4];
    delete c4++;
    delete []c4;
    // Case 5:
    volatile char *c5 = new char[4];
    for (int i = 0; i < 4; ++i)
        delete c5++;
    return 0;
}

Will the memory leak in each situation?

Dannyu NDos
  • 2,458
  • 13
  • 32

4 Answers4

8

Cases 1 through 3: No leaks.

Cases 4 and 5; the deallocations result in undefined behaviour. You are deleting from a pointer that does not have the value as originally allocated.

Why are there no leaks with 1 to 3? You match the appropriate delete or delete[] with the used new or new[]; and they are matched in pairs, one de-allocation for each allocation.

I assume that the sample is simple as provided to demonstrate the allocations, but be warned that the pointers are not being "reset" to NULL (or nullptr) so any access to the previously allocated memory once deallocated is undefined.


Side note on the std::move, does it make the c3 pointer nullptr? No it doesn't. The std::move doesn't actually "move" anything, it just changes the value category, see this answer and some sample code.

Community
  • 1
  • 1
Niall
  • 30,036
  • 10
  • 99
  • 142
6

Case 4 and 5 are undefined behaviour, so it's impossible to say whether or not the memory leaks.

For the other cases, the memory will not leak. However, it's worth stating that using new and delete at all is truly terrible and you should always use resource managing classes to hold the memory. Or to put it more simply, you shouldn't need to ask this question in the first place.

Puppy
  • 144,682
  • 38
  • 256
  • 465
1

Case 1:

volatile char *c1 = new char; 
volatile char *d1 = c1;
delete d1;

No memory Leaks. You are allocating memory and c1 points to it. Then a copy of the pointer c1 is happend (not the data). So d1 point to the same place that c1 points to now. Then, deleting d1 is equal to delete c1.

Case 2:

volatile char *c2 = new char[4];
volatile char *d2 = c2;
delete []d2;

Same as above except that you are allocating a sequence of memory and deleting a sequence of memory. So, no leaks.

Case 3:

volatile char *c3 = new char;
volatile char *d3 = std::move(c3);
delete d3;

You first allocate a memory and c3 points to it. Now you called a move operation. This move operation will move the address that c3 is holding to d3 without any change or move or copy on the actual data. After that, you deleted d3 which actually point to the same place that c3 was pointing to. So, no leaks.

Case 4&5: Undefined behaviour as other answers stated.

Humam Helfawi
  • 19,566
  • 15
  • 85
  • 160
1

It looks to me as if you are under the assumption that new char[5] performs 5 separate news for individual chars. (To me that seems to explain why you came up with cases 4 and 5).

But this is not the case; For example, c4 points to a single block of allocated storage that is (at least) large enough to hold 4 chars. You cannot delete individual parts of it, you can only delete all of it.

The difference between new/delete and new[]/delete[] is explained quite well in the C++ Super FAQ.

In your program:

// Case 1:
volatile char *c1 = new char; // Allocates enough space for 1 char
volatile char *d1 = c1;
delete d1;                    // Frees the space allocated
// Case 2:
volatile char *c2 = new char[4]; // Allocates enough space for a 4-char array
volatile char *d2 = c2;
delete []d2;                     // Frees that space
// Case 3:
volatile char *c3 = new char;    // Same as in case 1
volatile char *d3 = std::move(c3); // c3 is not nullptr
delete d3;                       // Same as in case 1
// Case 4:
volatile char *c4 = new char[4]; // Same as in case 2
delete c4++;                     // should be delete[], then same as case 2
delete []c4;                     // undefined behavior
// Case 5:
volatile char *c5 = new char[4]; // Same as in case 2
for (int i = 0; i < 4; ++i)
    delete c5++;                 // doesn't make sense, undefined behavior
return 0;
mindriot
  • 5,413
  • 1
  • 25
  • 34