• STL容器存储的内容动态分配情况下的内存管理


    主要分两种情况:存储的内容是指针;存储的内容是实际对象。

    看以下两段代码,

    1. typedef pair<VirObjTYPE, std::list<CheckID>*> VirObj_CheckID_pair;
    2. class LangChecker
    3. {
    4. public:
    5.     LangChecker();
    6.     ~LangChecker();
    7.    
    8.     void Register(VirObjTYPE type, CheckID id);
    9. private:
    10.     std::map<VirObjTYPE, std::list<CheckID>*> _registered_checker;
    11.     std::map<VirObjTYPE, std::list<CheckID>*>::iterator _registered_iter;
    12. };
    1. void LangChecker::Register(VirObjTYPE type, CheckID id)
    2. {
    3.     _registered_iter = _registered_checker.find(type);
    4.     if(_registered_iter == _registered_checker.end())  //not found
    5.     {
    6.         std::list<CheckID>* newlist = new list<CheckID>;
    7.         (*newlist).push_back(id);
    8.         _registered_checker.insert(VirObj_CheckID_pair(type, newlist));
    9.     }
    10.     else
    11.     {
    12.         (*(*_registered_iter).second).push_back(id);
    13.     }
    14. }
    15. LangChecker::~LangChecker()
    16. {
    17.     for(_registered_iter = _registered_checker.begin(); 
    18.             _registered_iter != _registered_checker.end(); _regeristered_iter++)
    19.     {
    20.         delete (*_registered_iter).second;
    21.     }
    22. }
    第二段代码中,Register函数动态生成指针newlist指向list<CheckID>对象,对象的内存分配在堆上;然后,将该指针insert到map容器——_registered_checker中。注意,STL容器在运行push_back/push_front/insert等操作时,会又一次为要插入进来的内容new对应的内存(在这里,会为type和newlist指针(!不是newlist指向的对象!)分配堆内存——32位系统下指针仅仅占4字节),这些操作分配的内存STL自己会管理不用我们担心,newlist指针也是局部变量自己会死亡。insert之后该map容器中的VirObjTYPE=type、list<CheckID>指针和newlist都指向一样的堆内存注意,newlist所指向的堆内存,是须要我们自己来释放的,这一步在析构函数里完毕比較合适。

        以下是第二种写法,将数据成员_registered_checker类型改为,
    1. std::map<VirObjTYPE, std::list<CheckID>> _registered_checker;
    2. std::map<VirObjTYPE, std::list<CheckID>>::iterator _registered_iter;
    对应的函数改为,
    1. typedef pair<VirObjTYPE, std::list<CheckID>> VirObj_CheckID_pair;
    2. void LangChecker::Register(VirObjTYPE type, CheckID id)
    3. {
    4.     _registered_iter = _registered_checker.find(type);
    5.     if(_registered_iter == _registered_checker.end())  //not found
    6.     {
    7.         std::list<CheckID>* newlist = new list<CheckID>;
    8.         (*newlist).push_back(id);
    9.         _registered_checker.insert(VirObj_CheckID_pair(type, *newlist));
    10.         delete newlist;
    11.     }
    12.     else
    13.     {
    14.         (*_registered_iter).second.push_back(id);
    15.     }
    16. }
    这时,map容器里的第二成员不再是指针而是实际的对象了,所以在insert时要把对应的对象*newlist插入到map中,这时,insert操作会为type和*newlist新分配堆内存(这里分配的是list<CheckID>对象、而非指针的内存),这块内存会由STL自己负责释放。insert后map容器中的VirObjTYPE=type、list<CheckID>=*newlist。注意,我们new出来的newlist所指向的内存,须要我们在newlist变量失效之前手动释放!所以,这里的内存释放分别由STL和Register函数完毕,析构函数里就不用做什么了。

        比較两种写法,后者申请和释放list<CheckID>对象内存的动作更为频繁,是前者的两倍。当list<CheckID>对象较大(仅仅要比指针的4字节大)时,性能上来说前者更好。

  • 相关阅读:
    重构代码
    我的菜单在母版页,如何更改菜单点击后的效果
    ASP.NET网页显示LED字体
    点击一次铵钮产生一个新文本框,分别输入值,然后获取
    linux不同信号之间发送信号测试
    UCOSII移植ARM的笔记
    C语言 return返回值的作用
    C语言 return没有返回值.
    linux c语言链表的简单应用之创建链表
    sizeof与strlen的用法
  • 原文地址:https://www.cnblogs.com/mfrbuaa/p/4301012.html
Copyright © 2020-2023  润新知