Chinaunix

标题: 关于new和delete,帮忙测试一下下面的代码。 [打印本页]

作者: kiffa    时间: 2008-10-20 02:33
标题: 关于new和delete,帮忙测试一下下面的代码。
我手头没有win的编译器,所以希望有vs、vc的能帮我测试一下下面的代码,看看输出结果是什么。用gcc的也顺便测试一下,我看看各个版本是否有差别。

class A
{
    public:
             int i;
             ~A(){cout << "haha" << endl;}
};


int main()
{
    A *p = new A[3];
   
    int *ip = (int*)(p - 1);
    *ip = 5;
   
    delete []p;
}



我这里的测试结果是输出 5 个 "haha"。
作者: blizzard213    时间: 2008-10-20 02:52
原帖由 kiffa 于 2008-10-20 02:33 发表
我手头没有win的编译器,所以希望有vs、vc的能帮我测试一下下面的代码,看看输出结果是什么。用gcc的也顺便测试一下,我看看各个版本是否有差别。

class A
{
    public:
             int i;
          ...

vc2005
5个 haha

可以解释一下吗?
感觉是p前一个int为记录数组大小的cookie。。。

[ 本帖最后由 blizzard213 于 2008-10-20 02:56 编辑 ]
作者: cj_gameboy    时间: 2008-10-20 08:19
提示: 作者被禁止或删除 内容自动屏蔽
作者: voodoo_cat    时间: 2008-10-20 08:21
vs2008也是5个haha。

ls说法应该是正确的。
作者: disheng727    时间: 2008-10-20 09:21
厉害,原来P-1的存储位置为该动态存储元素的个数。将其改成5,就调用了5次析构,如果改成7,也就将调用7次析构。
作者: alexhappy    时间: 2008-10-20 09:28
原帖由 disheng727 于 2008-10-20 09:21 发表
厉害,原来P-1的存储位置为该动态存储元素的个数。将其改成5,就调用了5次析构,如果改成7,也就将调用7次析构。

真有此事?我去测试一下。。。。
作者: 紫色的撒加    时间: 2008-10-20 10:33
所有编译器都这样吗?
作者: mik    时间: 2008-10-20 11:14
用 A*p = new A[3];  来建个A object 数组的模型的这样的:

                ----------
                        |          |      A[2]
                        ----------
                        |          |       A[1]
                        ----------
                        |          |       A[0]
                        ----------       <--------- p
                        |    3    |      size ( new 返回)
                        ----------      


int *ip = (int*)(p - 1); 将 size 改成 5
作者: disheng727    时间: 2008-10-20 11:28
int *ip = (int*)(p - 1);

好像有点不对吧,这种情况下只有当该类对象的大小刚好为一个指针的大小才成立,如若把A的成员int i改为char ch,就有点问题,觉得应该是:int *ip = (int*)(p) - 1;
作者: blizzard213    时间: 2008-10-20 11:29
原帖由 mik 于 2008-10-20 11:14 发表
用 A*p = new A[3];  来建个A object 数组的模型的这样的:

                ----------
                        |          |      A[2]
                        ----------
                         ...

请问下 这个应该只是一种通用的实现方式吧 标准不太可能规定这个
作者: blizzard213    时间: 2008-10-20 11:30
原帖由 disheng727 于 2008-10-20 11:28 发表

好像有点不对吧,这种情况下只有当该类对象的大小刚好为一个指针的大小才成立,如若把A的成员int i改为char ch,就有点问题,觉得应该是:int *ip = (int*)(p) - 1;

拜托 p只是指针。。。 其sizeof在一个特定平台上是一个特定值
怎么和对象大小扯上关系了。。
作者: mik    时间: 2008-10-20 11:34
原帖由 blizzard213 于 2008-10-20 11:29 发表

请问下 这个应该只是一种通用的实现方式吧 标准不太可能规定这个


不知道,没看过C++标准,偶只是在VS2008下观察得来的,gcc也是一样
作者: disheng727    时间: 2008-10-20 11:38
拜托 p只是指针。。。 其sizeof在一个特定平台上是一个特定值
怎么和对象大小扯上关系了。。

class A
{
    public:
             //int i;
             char ch;
             ~A(){cout << "haha" << endl;}
};


int main()
{
    A *p = new A[3];
   
    int *ip = (int*)(p - 1);
    *ip = 5;
   
    delete []p;
}

   
自己去试一下就知道输出结果如何。
作者: blizzard213    时间: 2008-10-20 11:50
原帖由 j1111011 于 2008-10-20 11:44 发表
A *p = new A[3];
   
    int *ip = (int*)(p - 1);
    *ip = 8;
   p[6] = 12;
   A bobo        =        p[3];
   bobo        =        p[4];
   bobo = p[5];
   bobo        =        p[6];
   bobo        =        p[7];
    delete []p;

我又尝试 ...

高度中没报什么错?
什么意思
作者: ztz0223    时间: 2008-10-20 15:34
在《inside c++ object model》里面就说到过这个东西
不同的编译器的实现会不同
但是现在貌似统一的挺不错了,一般的会在一个new或者malloc分配的空间的前面和后面放一段空间的cookies
前面是分配的个数符号
后面是分配的终止符号
符号会因为不同的类的分配而不同!
作者: kiffa    时间: 2008-10-20 18:07
一个复杂一点的例子:

// A定义和第一个帖子定义一样

A *p = new A;
cout << (long)p << endl;
delete p;
A *p2 = new A;
cout << (long)p2 << endl;


你会发现p 和 p2 的值是一样的。

然后:

A *p = new A;
cout << (long)p << endl;
delete []p;  // 注意。

A *p2 = new A;
cout << (long)p2 << endl;

你会发现p 和 p2不同,其根本原因就是delete []p 这一句并没有释放内存。

new A的时候,p - 1中存放内存大小相关的数据,p - 2中为0,delete A 时访问p - 1得到内存大小,释放。

而delete []A时,把p - 1中的值作为分配对象的个数来调用析构函数,然后把p - 2的值作为内存大小释放,而这里的p - 2 其值为0,所以delete语句并没有释放内存。
作者: Godbach    时间: 2008-10-20 18:15
原帖由 cj_gameboy 于 2008-10-20 08:19 发表
我是新手,请教下,C++可以在unix上编译吗,原以为C++只能在win平台上编译,用vs编译,是不是我搞错了,也可以用gcc编译啊


C/C++都可以在LINUX和WINDOWS编译和运行的。
作者: kiffa    时间: 2008-10-20 18:15
同样:

new A[3];
delete A;

会把分配对象的个数当成内存大小的相关信息来释放,只要A不小于一个字节,那么就会导致内存释放不完全,造成泄露。


因此这不仅仅是析构函数调用次数不够的问题,还可能造成内存泄露,不过限定于编译器的特定实现。

[ 本帖最后由 kiffa 于 2008-10-20 18:18 编辑 ]




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2