0

In the program below I try to release memory for a std::map object.

#include <map>
#include <iostream>
#include <unistd.h>

int main() {
  // std::map<int, int> *mp = new std::map<int, int>;;
  std::map<int, int> mp;
  for(int i = 0; i < 999999; i++){
    // mp->insert(std::pair<int, int>(i, 999999-i )); 
    mp[i] = 999999-i;
  }

  delete &mp;
  // delete mp;
  pause();
}

Both versions of the program (with comments or uncomment current comments with commenting corresponding lines) compiles well, but when i try to release memory through delete &mp (aka, mp is the std::map itself, not a pointer to std::map), it tells me this strange error message:

test14_1(47555,0x7fff75c6f300) malloc: *** error for object 0x7fff5c601918: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
Abort trap: 6

Anybody knows why is this so?

Jens
  • 8,423
  • 9
  • 58
  • 78
beanmoon
  • 59
  • 2
  • 8

4 Answers4

4

There are two aspects here in your program.

Allocation of the ::map

By declaring your variable like you did, you are creating a ::map object in the scope of the function main(). The map is allocated on the stack of that function and automatically initialized when that function (i.e. the function scope { .. }) is entered.

Freeing of the ::map

Because the map was allocated on the stack when the scope was entered, it is automatically deleted when the function returns (i.e. the function scope closes). You do not need to worry about this.

What you do...

By calling the delete operator you are trying to free memory from the process heap. The delete operator takes as argument a pointer to the allocated memory, and by writing &mp you are creating such a pointer. However, because the mp object lives on the stack where you allocated it, the C++ runtime gives you the error that the pointer being freed was not allocated on the heap using the new operator.

Interestingly, you already have the right code in your program, you just paired the allocation/free incorrectly:

// Allocate the memory on the heap, and free it. 
// mp is a pointer to the allocated map.
int main() {
    std::map<int, int> *mp = new std::map<int, int>;
    // do stuff, e.g. mp->insert()
    delete mp;
}
// Allocate the memory on the stack, freed automatically.
// mp is a reference to the allocated map.
int main() {
    std::map<int, int> mp;
    // do stuff, e.g. mp.insert()
    // no need to free mp explicitly!
}

Note

You may want to learn about how C/C++ programs organize their memory: heap and stack memory allocation (take a look here or here), and the difference between a pointer and a reference to a memory allocation (take a look here or here).

PS: You got lucky with the error message. In optimized code with memory safety disabled (e.g. gcc's memory sanitizer) your program would behave non-deterministically and maybe crash.

Community
  • 1
  • 1
Jens
  • 8,423
  • 9
  • 58
  • 78
3

You don't need to delete std::map, since you didn't allocate memory using new operator. All standard containers like std::map are capable to manage their memory themselves. They are internally using allocator for memory management.

Steephen
  • 14,645
  • 7
  • 40
  • 47
1

Using

  std::map<int, int> mp;

  delete &mp;

is analogous to:

  int i;
  delete &i;

which is wrong.

You need to deallocate memory by using delete only when an object was allocated using new.

Objects created on the stack are deleted automatically. If the destructor of the class does the right things, client code does not have anything more to do. In the case of std::map, the destructor will do the necessary deallocation. Your function doesn't have to do anything.

R Sahu
  • 204,454
  • 14
  • 159
  • 270
-1

This is basic RAII.

Any stack local object, that includes simple variables of type int/float etc. or as in your case a container, is destroyed at the end of the scope.

With your explicit destruction,

{
   vector<int> v1;
   map<int,int> m1;

   delete &m1;
} // implicit destruction of v1 and m1!

With your explicit delete statement, the resulting code will end up freeing of already freed memory.

KalyanS
  • 527
  • 3
  • 8
  • Your last sentence is simply wrong. There isn't a _double free_ problem in this code, it is an error to call `delete` with an address that wasn't obtained by calling `new`. – Blastfurnace May 29 '15 at 04:34
  • It is not an error, it is undefined behavior. Based on the bits present in the memory location, the explicit delete may work, for all you know! But, what is certain is that there are two delete's happening. Neither the language nor the compiler prohibit calling delete on any address. Results are undefined. Even if you get away with it, the double free is deterministically wrong! – KalyanS May 29 '15 at 04:38