Aug 17

关于delete 不指定

felix021 @ 2009-8-17 15:07 [IT » 程序设计] 评论(4) , 引用(0) , 阅读(4976) | Via 本站原创 | |
前两天在Dutor(或者是Ivan?)的Blog看到了一篇文章:
关于free和delete http://www.dutor.net/index.php/2009/08/free-delete/

以前没有仔细考虑过这个问题,因此和Sandy讨论了一下,得出了初步结果,总结一下放在这里吧。

---传说中的分割线---

先看一段代码:
#include<iostream>
class T{
public:
    int *a;
    T() {
        a = new int[1048576];
        std::cout << "T()" << endl;
    }
    ~T() {
        delete[] a;
        std::cout << "~T()" << endl;
    }
};

int main() {
    T *a = new T;
    delete (char*)a;
}

这段代码的前面还是比较好理解的,关键在于,这最后的 delete (char *)a; 它究竟做了什么事情?
1. 它释放了多少内存——是释放了一个char*指向的内存,还是当初new分配的那些内存?
2. 它是否调用了class T的析构函数?

下面是我和Sandy的讨论结果,针对以上两个问题的分析,以及一点延伸的探讨。

1. 释放了多少内存。
回头想想C提供的malloc/free函数,这小俩口处理的都是void*类型的指针,而且当free时只要告诉其指针即可。
也就是说,malloc函数多做了一些事情,让程序在某处记住了分配的内存大小,当free时,对应找到这个大小进行释放。
因此我们有理由认为,new/delete这对黑白脸做法也是类似的(没有小心求证,如果不对,请大牛指出):
-- new从堆上申请内存,是先进行记录,包括新内存的地址以及申请的长度,然后才把地址返回给申请者。
-- delete根据释放者提交的地址,在记录中查找这个地址,然后找到其长度,然后回收内存。。
故此我们认为,它释放的内存是new分配的那些内存,与传入的指针类型无关。

2. 是否调用了相应的析构函数。
这个问题很容易验证,把上面的程序跑一遍就可以了。
结果就是,输出了 "T()" 这一行,说明只调用了构造函数而没有调用析构函数。
仔细想想,其实这很容易理解。
隐约记得STL之父(Or C++之父?)说过一句话,你有很多事情做,但是编译器没有。
C++编译器被设计成帮你完成了很多琐碎的事情,很典型的一件事就是,编译期类型推导。
因此你在cout的时候也不需要指定输出类型(%d%x%c...)
new一个东西以后不需要像malloc那样进行强制类型转换了,还自动调用class 的构造函数,
delete一个指向class的指针时,也根据指针的类型自动添加了调用该class析构函数的代码。
而上面给出的代码,最终交给delete的是一个char *类型的指针
因此编译器添加的代码就不会涉及到class T的析构函数。
如果你是转换成另一个class Q的指针,那么就会调用Q的析构函数。有兴趣的话可以自己写程序证实一下。

3. 它会导致严重的后果吗?
答案是会。
比如上面给出的程序,造成了内存泄漏:预期在析构函数中释放的 T::a 指向的内存,但是析构函数最终没有被执行。

4. 它会导致更严重的后果吗?
答案还是会。
这一点是Sandy提出来的:在C++中,operator new/delete是可以被重载的。
如果一个class的operator new/delete被重载了,它将以它自己的方式去管理(分配/回收)内存。
比如说以内存池的方式;或者是在栈上进行分配的内存。
如果你使用这种方式去delete一个改变了类型的指针,那么结果就是,采用了不同的管理方式去回收这个内存。
——就好比你malloc出来的内存被delete掉了
传说中的换妻啊。。。后果就是对方崩溃了。。。嗯。

--------传说中的分割线--------

这个问题到这里差不多了,实际使用中应该不会有谁这么脑残的吧,嗯。
进行这样的一些分析,主要是希望能够更深入地理解C++这一块的内容。

还没有确切解决的疑问就是第一个——
new/delete 释放的内存块大小是否关乎指针类型?希望有大牛释疑。

另外顺便提一下,我觉得当在C++中需要使用对class进行强制类型转换的时候,
应该好好考虑一下,这程序是不是在设计上出了什么问题,因为这么做会增加程序的耦合性。
当然,在某些时候你的确会需要用到这种做法,因为这样可以增加程序的动态性(许多Java程序依赖于此)。



欢迎扫码关注:




转载请注明出自 ,如是转载文则注明原出处,谢谢:)
RSS订阅地址: https://www.felix021.com/blog/feed.php
晴空
2011-1-23 18:02
很不错,谢谢楼主
ivan Homepage
2009-8-17 16:25
windows里面有个_heap_alloc的函数
ivan Homepage
2009-8-17 16:15
换妻……fearnew了10个std::string给指针pstr,会得到*((int*)ptrs - 1) == 10(g++好像是*((int*)ptrs - 2))。对堆管理不是太了解,如果这是由操作系统来管理的,那不管new还是malloc,delete还是free,底层的机制不都该一样吗?有没有这种可能,new调用了free或者类似的函数或宏?
Sandy
2009-8-17 15:39
沙发应当归我。。
1、2、3给[B]一下吧。。
分页: 1/1 第一页 1 最后页
发表评论
表情
emotemotemotemotemot
emotemotemotemotemot
emotemotemotemotemot
emotemotemotemotemot
emotemotemotemotemot
打开HTML
打开UBB
打开表情
隐藏
记住我
昵称   密码   *非必须
网址   电邮   [注册]