简化C++内存管理,避免内存泄露的…

本文介绍了C++中三种有效的内存管理方法:智能指针、真正的垃圾回收和级联删除。重点探讨了级联删除方法的实现及其适用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    C++不像java和c#那样有垃圾回收机制,所以内存泄露是个比较头疼的问题(谁会忘记写delete?谁都会!),有几种缓解之道:
    1)智能指针(推荐boost::shared_ptr)。
    2)真正的垃圾回收,参考http://www.hpl.hp.com/personal/Hans_Boehm/gc/,这个我没用过,因为据说不实用:)故本文不讨论。
    3)这是从QT中学到的方法,将堆中分配的内存组成森林,然后删除根结点的时候级联删除所有子结点。这样就简化了内存管理:从管理所有内存到只要管理根结点。

    先讨论方法1:
    对于智能指针来说,如果存在互相引用现象,则会导致内存无法释放,所以使用时务必要规避这种情况。有人不用智能指针而是自己为分配的内存管理引用计数,这有点类似于重新造轮子,很多情况下是不必要的。
    避免发生互相引用并不那么困难,只要遵守这两条原则:
    1)如果可以把两个类理解成"整体-部分"关系(如一个是容器,一个是元素),则整体类对象可以持有部分类对象的智能指针,部分类对象不能持有整体类对象的智能指针。整体类对象的生命周期必须真包含部分类对象的生命周期。如果部分类对象中需要保存整体类对象的引用,可以使用原生指针(这是安全的,因为整体类活得久)、引用(推荐,因为使用方便且更安全,用过就知道)或者weak_ptr(比较安全但效率没那么高)。
    2)除此之外,任何对象不持有其他对象的智能指针,与其他对象协作的唯一方式是通过参数传入其他对象的智能指针。
    但知易行难,没办法检查编程时是否遵守了这两条原则。

    再讨论方法3:
    这种方法的优点是实现简单,逻辑清晰,效率高。缺点是对异步和closure的支持不好——鬼知道实际调用的时候,指针指向的那货是否还健在。加入引用计数?哇靠,那还不如直接用智能指针。
    但是当程序中不存在异步调用和closure要求的时候,不失为一种可行的内存管理方法——大部分客户端和基于阻塞IO的服务端一般满足该条件。即使有异步调用,只要保证要用到的东东在实际调用前不会被干掉(比如那些东东是永存的),也可以使用该方法。
    实际编程中如果想要使用该方法,需要基础类库的支持。不然一个个去写基础类库(如vector)的wrapper,实在很繁琐。所以这个从QT中学到的方法,基本上也只能在QT中用了。
    下面给出方法3的一种简易实现,CascadeElem类是关键(爆简单),其他都是示例代码哈。
=================================代码的分割线=============================================
#include <iostream>
#include <vector>

using namespace std;

class CascadeElem    
{
public:   
    CascadeElem(CascadeElem* parent)    
    {
        if (parent != NULL)
        {
            parent->children_elem_.push_back(this);
        }
    }
    virtual ~CascadeElem()
    {
        std::size_t cnt = children_elem_.size();
        for (std::size_t i = 0; i < cnt; ++i)
        {
            delete children_elem_[i];
        }
    }
private:   
    std::vector<CascadeElem*> children_elem_;
};

class Child : public CascadeElem
{
public:
    Child(CascadeElem* parent, int num)
        : CascadeElem(parent)
        , num_(num)
    {
    }
    ~Child()
    {
        cout << "~Child(" << num_ << ")"  << endl;
    }
private:
    int num_;
};

class Foo : public CascadeElem
{
public:
    Foo(CascadeElem* parent, int num)
        : CascadeElem(parent)
        , num_(num)
    {
        for (int i = 0; i < num; ++ i)
        {
            new Child(this, i);            
        }
    }
    ~Foo()
    {
        cout << "~Foo(" << num_ << ")"  << endl;
    }
private:
    int num_;
};

int main(int argc, char* argv[])
   
    Foo* root = new Foo(NULL, 0);
    Foo* ptr1 = new Foo(root, 1);
    Foo* ptr2 = new Foo(ptr1, 2);
    Foo* ptr3 = new Foo(ptr2, 3);
    Foo* ptr4 = new Foo(root, 4);    
    delete root;

    return 0;
}

=================================结果的分割线=============================================
~Foo(0)
~Foo(1)
~Child(0)
~Foo(2)
~Child(0)
~Child(1)
~Foo(3)
~Child(0)
~Child(1)
~Child(2)
~Foo(4)
~Child(0)
~Child(1)
~Child(2)
~Child(3)
可见所有new的对象都被级联删除了。
   




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值