以前写过一篇关于delete的日志,那里提到的只是一个实验而已,我想正常人不会犯那么弱智的错误吧。但接下来的这个问题就不得不加倍留心了。直接看代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>
#include <pthread.h>
using namespace std;
 
class M
{
    public:
        M(){}
        ~M()
        {
            cout<<"M destructed..."<<endl;
        }
    private:
        int i;
};
class B
{
    public:
        B(){}
        //! virtual ~B(){}
        ~B(){}
};
class D: public B
{
    public:
        D(){}
        ~D(){}
    private:
        M m;
};
 
int
main()
{
    B * pb = new D;
    delete pb;
    return 0;
}

表明看来似乎合情合理,由于C++的多态特性,允许我们将一个子类地址赋给父类型的指针pb,释放对象时理所当然的对pb进行delete。但,在程序运行时,并没有输出M destructed…,即D::m的析构函数没有被调用,而m的析构函数是需要D::~D()来调用的,所以子类D的析构函数也没有被调用。这是很容易理解的,因为父类的析构函数不是virtual的。由此,我们得出结论,用来继承的父类的析构函数总应该是virtual的,除非你确定它绝对不会被用于多态。关于这一点,《Effective C++》里面已经讲到了。

除了上面的问题,我们还应该关心的是,尽管析构函数没有被调用,那M::i的空间被释放了吗?It’s a question!由于析构函数没有被调用,那么释放M::i的任务就完全落在了delete身上的了,那么delete做到了吗?It’s a very question!这又回到了上一篇日志中所描述的问题上了。我的观点是delete做到了它应该做的事情,它只负责释放当初new申请的空间,即对象本身,至于对象里面是否有动态申请的内存,那就不是delete而是对象析构函数自己的工作了。

Tags: ,,.
你好!除了代码,此处没有多少原创之物,皆为本人搜集、整理、总结之记录与心得,欢迎转载分享!转载时请尽量注明出处,将不胜感激。祝你健康、快乐!
Home

Be the first to comment on this entry.

Name(required)
Mail (required),(will not be published)

RFC: Request For Comments. Orz..

Website(recommended)