C++析构机制实验

C++析构机制实验

内存管理是c++不同于其它高级语言的一门很深的学问,要想管理好内存,首先要熟悉c++的特性,这样才能在写代码时做出合适的假设,避免内存泄露等难以发现的顽疾。

众所周知析构一般是用来释放堆栈空间的。对于程序员来说栈空间基本上都会由编译器帮我们处理,尤其需要我们来经营的是堆空间。如果一个结构体/类不存在对象指针,那么它基本可以不用写析构函数。

下文概念执行析构:执行析构指释放对象的资源,需要注意执行析构不等同于执行析构函数(这其中还包括一个隐式的递归资源释放,下文会体现)

下文每提到一个机制,都会给出一个相应的测试用例,请先思考输出结果后再进行执行比对。

析构的发生

当一个栈帧在释放时,其上的结构若再无法被其它代码直接访问则会被自动析构

  • 如果一个栈帧结束,会执行栈上所有结构的析构
//测试用例
class Bird
{
    public:
        Bird(){}
        ~Bird()
        {
            cout<<"Bird was killed";
        }
};
int main()
{
    Bird bird;
}
  • 如果一个栈帧结束,但某个结构作为返回值返回并被父栈帧接收,那么就不会在子栈帧被析构。反之,如果没返回,或者返回了但没有接收,都会被执行析构
struct T
{
    char name;
    T(char name):name(name){}
    ~T()
    {
        cout<<name<<":  I'm deleted!"<<endl;
    }
};
T getTs()
{
    T n('N');//没有被返回
    T r('R');
    return r;
}
T getT()
{
    T r('!');
    return r;
}
int main()
{
    T t=getTs();//返回被接收
    getT();//返回未接收
    cout<<"main over"<<endl;
}

析构的自动递归

执行析构不仅限于执行"析构函数",还包括隐式地析构成员对象

  • 当一个对象被析构,它的成员对象会被递归析构。(但是他的成员指针不会,堆上的需要我们手动delete)
    • 一个对象的成员指针需要在析构函数内手动检查并析构(delete)。
  • 析构的顺序总是先调用析构函数,后析构成员对象
class Wing
{
    public:
        Wing(){}
        ~Wing()
        {
            cout<<"Wings were broken";
        }
};
class Bird
{
    Wing wing;
    public:
        Bird(){}
        ~Bird()
        {
            cout<<"Bird was killed\n";
        }
};
int main()
{
    Bird bird;
}

通过delete来手动执行堆上对象的析构

class Wing
{
    public:
        Wing(){}
        ~Wing()
        {
            cout<<"Wings were broke";
        }
};
class Bird
{
    Wing wing;
    public:
        Bird(){}
        ~Bird()
        {
            cout<<"Bird was killed\n";
        }
};
int main()
{
    Bird* bird=new Bird();
    delete bird;
}
  • 析构函数不止"析构函数",调用析构函数等同于调用析构
    • c++不建议通过显式调用析构函数来析构对象
class Wing
{
    public:
        Wing(){}
        ~Wing()
        {
            cout<<"Wings were broke\n";
        }
};
class Bird
{
    Wing wing;
    public:
        Bird(){}
        ~Bird()
        {
            cout<<"Bird was killed\n";
        }
};
int main()
{
    Bird* bird=new Bird();
    bird->~Bird();
    cout<<"main over"<<endl;
}

继承中的析构

  • 一个派生类在析构时会先析构自身,后析构基类
struct DNA
{
    ~DNA()
    {
        cout<<"DNA"<<":  I'm deleted!"<<endl;
    }

};
struct Animal
{
    DNA dna;
    Animal(){}
    ~Animal()
    {
        cout<<"Animal"<<":  I'm deleted!"<<endl;
    }
};
struct Paw
{
    ~Paw()
    {
        cout<<"Paws"<<":  I'm deleted!"<<endl;
    }
};
struct Cat : public Animal
{
    Paw paw;
    Cat(){}
    ~Cat()
    {
        cout<<"Cat"<<":  I'm deleted!"<<endl;
    }

};
int main()
{
    Cat cat;
}
  • 一个基指针指向派生对象,析构时只会析构基对象
struct Animal
{
    Animal(){}
    ~Animal()
    {
        cout<<"Animal"<<":  I'm deleted!"<<endl;
    }
};
struct Cat : public Animal
{
    Cat(){}
    ~Cat()
    {
        cout<<"Cat"<<":  I'm deleted!"<<endl;
    }

};
int main()
{
    Animal *anim=new Cat;
    delete anim;

}
  • 若将基虚构函数虚化,则可正确析构派生对象

所以说基类的析构函数一定要加virtual!

struct Animal
{
    Animal(){}
    virtual ~Animal()
    {
        cout<<"Animal"<<":  I'm deleted!"<<endl;
    }
};
struct Cat : public Animal
{
    Cat(){}
    ~Cat()
    {
        cout<<"Cat"<<":  I'm deleted!"<<endl;
    }

};
int main()
{
    Animal *anim=new Cat;
    delete anim;

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值