免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 5280 | 回复: 7
打印 上一主题 下一主题

[C++] 析构函数内存释放问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2015-09-30 19:02 |只看该作者 |倒序浏览
本帖最后由 tianhailong 于 2015-09-30 19:25 编辑

今天遇到一个比较奇怪的问题,没搞明白,请教一下:
下边的程序 在构造函数中申请了堆内存,析构时释放,
执行了2次构造函数,3次析构函数,就会出现对一块内存两次释放,
可是程序还能正常执行,也不会coredump,不知道为什么呢?

#include <iostream>
using namespace std;

class Complex
{
public:
  float realPart;
  float virtualPart;
  char *p;
    Complex (float r, float v)
  {
    realPart = r;
    virtualPart = v;
    p = (char *) malloc (10);
    printf ("Construct %p\n", p);
  }
   ~Complex ()
  {
    free (p);
    printf ("Destruct %p\n", p);
  }
};


Complex
operator - (Complex c)
{
  return Complex (-c.realPart, -c.virtualPart);
}

int
main ()
{
  Complex c1 (11.1f, 22.2f);
  c1 = -c1;
  return 0;
}

执行结果如下:

Construct 0x502010
Construct 0x502030
Destruct 0x502030
Destruct 0x502010
Destruct 0x502030

可以看到,对 0x502030 做了两次释放,我觉得应该会coredump
但是却没有

论坛徽章:
89
水瓶座
日期:2014-04-01 08:53:31天蝎座
日期:2014-04-01 08:53:53天秤座
日期:2014-04-01 08:54:02射手座
日期:2014-04-01 08:54:15子鼠
日期:2014-04-01 08:55:35辰龙
日期:2014-04-01 08:56:36未羊
日期:2014-04-01 08:56:27戌狗
日期:2014-04-01 08:56:13亥猪
日期:2014-04-01 08:56:02亥猪
日期:2014-04-08 08:38:58程序设计版块每日发帖之星
日期:2016-01-05 06:20:00程序设计版块每日发帖之星
日期:2016-01-07 06:20:00
2 [报告]
发表于 2015-09-30 19:57 |只看该作者
执行了不止2次的构造函数吧。

你看到2次,是因为编译器给你构造的那个copy constructor里面没有print语句。

论坛徽章:
1
2015亚冠之阿尔艾因
日期:2015-08-24 15:46:57
3 [报告]
发表于 2015-10-08 10:49 |只看该作者
本帖最后由 何必抱怨 于 2015-10-08 10:51 编辑

事实上是malloc了一次,然后却free了两次。

在vs2008下我试了下,debug模式下是会报错的。
在g++ 4.6.3下试了一下,不会报错

事实上lz的问题等价于:
  1.         char *p1 = (char *) malloc (10);
  2.         char *p2 = (char *) malloc (10);
  3.         free(p1);
  4.         free(p2);
  5.         free(p1);
复制代码
为什么不会报错。

我尝试了一下,如果把上面的代码改为:
  1.         char *p1 = (char *) malloc (10);
  2.         char *p2 = (char *) malloc (10);
  3.         free(p1);
  4.         free(p1);
复制代码
在vs和g++下都会报错的。
中间插入了free(p2);之后,vs下会报错,g++下不会报错,这个暂时不知道什么原因。

论坛徽章:
14
水瓶座
日期:2014-06-10 09:51:0215-16赛季CBA联赛之江苏
日期:2017-11-27 11:42:3515-16赛季CBA联赛之八一
日期:2017-04-12 14:26:2815-16赛季CBA联赛之吉林
日期:2016-08-20 10:43:1215-16赛季CBA联赛之广夏
日期:2016-06-23 09:53:58程序设计版块每日发帖之星
日期:2016-02-11 06:20:00程序设计版块每日发帖之星
日期:2016-02-09 06:20:0015-16赛季CBA联赛之上海
日期:2015-12-25 16:40:3515-16赛季CBA联赛之广夏
日期:2015-12-22 09:39:36程序设计版块每日发帖之星
日期:2015-08-24 06:20:002015亚冠之德黑兰石油
日期:2015-08-07 09:57:302015年辞旧岁徽章
日期:2015-03-03 16:54:15
4 [报告]
发表于 2015-10-08 11:12 |只看该作者
回复 1# tianhailong


    "undefined behavior" 又不代表一定会coredump

free.JPG (45.13 KB, 下载次数: 49)

free.JPG

论坛徽章:
14
水瓶座
日期:2014-06-10 09:51:0215-16赛季CBA联赛之江苏
日期:2017-11-27 11:42:3515-16赛季CBA联赛之八一
日期:2017-04-12 14:26:2815-16赛季CBA联赛之吉林
日期:2016-08-20 10:43:1215-16赛季CBA联赛之广夏
日期:2016-06-23 09:53:58程序设计版块每日发帖之星
日期:2016-02-11 06:20:00程序设计版块每日发帖之星
日期:2016-02-09 06:20:0015-16赛季CBA联赛之上海
日期:2015-12-25 16:40:3515-16赛季CBA联赛之广夏
日期:2015-12-22 09:39:36程序设计版块每日发帖之星
日期:2015-08-24 06:20:002015亚冠之德黑兰石油
日期:2015-08-07 09:57:302015年辞旧岁徽章
日期:2015-03-03 16:54:15
5 [报告]
发表于 2015-10-08 12:28 |只看该作者
本帖最后由 lxyscls 于 2015-10-08 12:29 编辑

回复 3# 何必抱怨
  1. void
  2. public_fREe(void* mem)
  3. {
  4.   mstate ar_ptr;
  5.   mchunkptr p;                          /* chunk corresponding to mem */

  6.   void (*hook) (__malloc_ptr_t, __const __malloc_ptr_t)
  7.     = force_reg (__free_hook);
  8.   if (__builtin_expect (hook != NULL, 0)) {
  9.     (*hook)(mem, RETURN_ADDRESS (0));
  10.     return;
  11.   }

  12.   if (mem == 0)                              /* free(0) has no effect */
  13.     return;

  14.   p = mem2chunk(mem);

  15.   ... ...

  16.   ar_ptr = arena_for_chunk(p);
  17.   _int_free(ar_ptr, p, 0);
  18. }
复制代码
对于较小的内存分配,都在chunk里面分配,使用_init_free()。
  1. static void
  2. _int_free(mstate av, mchunkptr p, int have_lock)
  3. {
  4.   INTERNAL_SIZE_T size;        /* its size */
  5.   mfastbinptr*    fb;          /* associated fastbin */
  6.   mchunkptr       nextchunk;   /* next contiguous chunk */
  7.   INTERNAL_SIZE_T nextsize;    /* its size */
  8.   int             nextinuse;   /* true if nextchunk is used */
  9.   INTERNAL_SIZE_T prevsize;    /* size of previous contiguous chunk */
  10.   mchunkptr       bck;         /* misc temp for linking */
  11.   mchunkptr       fwd;         /* misc temp for linking */

  12.   const char *errstr = NULL;
  13.   int locked = 0;

  14.   size = chunksize(p);

  15.   ... ...

  16.   /*
  17.     If eligible, place chunk on a fastbin so it can be found
  18.     and used quickly in malloc.
  19.   */

  20.   if ((unsigned long)(size) <= (unsigned long)(get_max_fast ())

  21.     ... ...

  22.     set_fastchunks(av);
  23.     unsigned int idx = fastbin_index(size);
  24.     fb = &fastbin (av, idx);

  25.     mchunkptr fd;
  26.     mchunkptr old = *fb;
  27.     unsigned int old_idx = ~0u;
  28.     do
  29.       {
  30.         /* Another simple check: make sure the top of the bin is not the
  31.            record we are going to add (i.e., double free).  */
  32.         if (__builtin_expect (old == p, 0))
  33.           {
  34.             errstr = "double free or corruption (fasttop)";
  35.             goto errout;
  36.           }
复制代码
为什么free(p1);free(p1);会"double free",没有细看代码,我个人的理解是:两次取得的chunk_size一样,所以它认为是"double free"。
为什么中间加了一个free(p2),就不会"double free"了,是因为再free(p1)的时候,chunk_size变了

因为p1,p2的大小都是10,所以它们都在fastbin里面分配;如果把p2设置成一个比较大的值,比如13B,free(p1);free(p2);free(p1);一样会"double free",因为p2分配的chunk和p1不一样,不影响第二次free(p1)时候的判断




论坛徽章:
0
6 [报告]
发表于 2015-10-09 17:50 |只看该作者
楼上已经回答你的问题了

我只提一下,
你的Complex对象在调用operator-传递参数的时候有拷贝构造,此外还有(编译器自动生成的)operator=的调用,这两处都是bit-wise的拷贝
如果你的class要管理内存,最好实现所有的copy ctor 和 operator=,否则很容易踩地雷(比如double free)
此外,用引用的方式传递函数参数,避免不必要的构造和析构

论坛徽章:
0
7 [报告]
发表于 2015-10-10 20:46 |只看该作者
那段代码里边是没有拷贝构造函数的,只有赋值回复 6# YEETA


   

论坛徽章:
1
2015亚冠之阿尔艾因
日期:2015-08-24 15:46:57
8 [报告]
发表于 2015-10-12 09:07 |只看该作者
回复 7# tianhailong
编译器自动生成的。


   
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP