为什么在我通过'删除'释放内存以便发生此错误时声明?

时间:2015-05-29 04:20:08

标签: c++

在下面的程序中,我尝试释放std::map对象的内存。

#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();
}

该程序的两个版本(带注释或取消注释当前注释并注释相应的行)编译得很好,但当我尝试通过delete &mp释放内存时(又名,mp是std :: map本身,而不是指向std :: map的指针,它告诉我这个奇怪的错误信息:

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

有人知道为什么会这样吗?

4 个答案:

答案 0 :(得分:4)

您的计划中有两个方面。

分配:: map

通过像你一样声明你的变量,你正在函数main()的范围内创建一个::map对象。地图在该函数的堆栈上分配,并在输入该函数(即函数scope { .. })时自动初始化。

释放:: map

因为在输入作用域时已在堆栈上分配了映射,所以在函数返回时会自动删除它(即函数作用域关闭)。你不必担心这个。

你做了什么......

通过调用delete运算符,您尝试从进程中释放内存。 delete运算符将指向已分配内存的指针作为参数,并通过编写&mp来创建这样的指针。但是,因为mp对象存在于您分配它的堆栈上,所以C ++运行时使用new运算符为您提供了堆上pointer being freed was not allocated的错误。

有趣的是,您已经在程序中拥有了正确的代码,您只是错误地配置了分配/免费:

// 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!
}

注意

您可能想了解C / C ++程序如何组织内存:堆和堆栈内存分配(看看herehere),以及指针和引用之间的区别内存分配(看看herehere)。

PS:你很幸运,错误信息。在禁用内存安全性的优化代码中(例如gcc&#39; s memory sanitizer),您的程序会表现得非确定并且可能会崩溃。

答案 1 :(得分:3)

您不需要删除std::map,因为您没有使用new运算符分配内存。像std::map这样的所有标准容器都能够自己管理它们的内存。他们在内部使用allocator进行内存管理。

答案 2 :(得分:1)

使用

  std::map<int, int> mp;

  delete &mp;

类似于:

  int i;
  delete &i;

这是错误的。

只有在使用delete分配对象时,才需要使用new释放内存。

自动删除在堆栈上创建的对象。如果类的析构函数做了正确的事情,客户端代码就没有更多的事情可做了。在std::map的情况下,析构函数将执行必要的释放。你的功能不需要做任何事情。

答案 3 :(得分:-1)

这是基本的RAII。

任何堆栈本地对象,包括int / float等类型的简单变量,或者就像容器一样,都会在范围的末尾销毁。

明确销毁,

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

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

使用显式删除语句,生成的代码最终将释放已释放的内存。