• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            安全的list

                好久沒有寫東西了,實(shí)在是忙,其實(shí),準(zhǔn)確說是懶。

                最近調(diào)試客戶端地圖管理的時(shí)候,老是出現(xiàn)對(duì)象在視野中進(jìn)進(jìn)出出后就會(huì)冒出個(gè)非法。而非法的原因大多跟list有關(guān),就是在list遍歷顯示列表的時(shí)候,出現(xiàn)了增刪操作,而這個(gè)是list不能容忍的。由于系統(tǒng)比較大,要改的地方也多,而且好多異常情況也不是一下子就能改好的,當(dāng)屏幕中的生物對(duì)象很多時(shí),就容易出現(xiàn)。

            想來想去,就想了一個(gè)能安全遍歷的list來解決問題。因?yàn)樵趯?shí)際上,當(dāng)遍歷到一個(gè)list的節(jié)點(diǎn)時(shí),會(huì)調(diào)用節(jié)點(diǎn)所含對(duì)象的update方法,該方法可能會(huì)觸發(fā)從地圖中刪除自己或者其他對(duì)象,這樣list就非法了。

            下面是對(duì)標(biāo)準(zhǔn)list的簡單封裝,使之具有安全遍歷的特性,遍歷過程中可以增刪任何節(jié)點(diǎn)。原理很簡單,就是內(nèi)部記住遍歷的當(dāng)前節(jié)點(diǎn),在刪除時(shí)做個(gè)比較。

            //==========================================================================
            /**
            * @file      : safelist.h
            * @author : PeakGao <peakgao163@163.com>
            * created : 2008-11-13   20:21
            * purpose : safe list
            */

            //==========================================================================

            #ifndef __safelist_h__
            #define __safelist_h__

            #include 
            <list>

            /** 安全list
            對(duì)標(biāo)準(zhǔn)list進(jìn)行了簡單封裝,使之具有安全遍歷的功能(即:在遍歷過程中,支持增刪節(jié)點(diǎn))

            // 普通遍歷
            for (safelist<int>::const_iterator it = list.begin(); it!=list.end(); ++it)
            {
                Info("val = "<<*it<<endl);
            }

            // 安全遍歷(允許在遍歷的過程中增刪任何數(shù)目的節(jié)點(diǎn))
            for (safelist<int>::iterator it=list.find_first(); it!=list.end(); it=list.find_next(it))
            {
                Info("val = "<<*it<<endl);
                if (*it == 3)
                {
                    list.erase(it);
                }
            }
            */

            template
            <class _Ty, class _Ax = std::allocator<_Ty> >
            class safelist : public std::list<_Ty, _Ax>
            {
            public:
                typedef typename std::list
            <_Ty, _Ax>    _Mybase;
                typedef typename safelist
            <_Ty, _Ax>        _Myt;
                typedef typename _Mybase::_Alloc        _Alloc;

            private:
                mutable _Nodeptr    _Cur;    
            /// the cursor for for_each

            public:
                safelist() : _Mybase(), _Cur(_Myhead) 
            { }
                
            explicit safelist(const _Alloc& _Al) : _Mybase(_Al), _Cur(_Myhead) { }
                
            explicit safelist(size_type _Count) : _Mybase(_Count), _Cur(_Myhead) { }
                safelist(size_type _Count, 
            const _Ty& _Val) : _Mybase(_Count, _Val), _Cur(_Myhead) { }
                safelist(size_type _Count, 
            const _Ty& _Val, const _Alloc& _Al) : _Mybase(_Count, _Val, _Al), _Cur(_Myhead) { }
                safelist(
            const _Mybase& _Right) : _Mybase(_Right), _Cur(_Myhead) { }
                safelist(
            const _Myt& _Right) : _Mybase(_Right), _Cur(_Myhead) { }
                template
            <class _Iter>
                safelist(_Iter _First, _Iter _Last) : _Mybase(_First, _Last), _Cur(_Myhead) 
            { }
                template
            <class _Iter>
                safelist(_Iter _First, _Iter _Last, 
            const _Alloc& _Al) : _Mybase(_First, _Last, _Al), _Cur(_Myhead) { }

                
            ~safelist()
                
            {
                    _Cur 
            = 0;
                }


                
            void clear()
                
            {
                    _Mybase::clear();
                    _Cur 
            = _Myhead;
                }


                iterator erase(iterator _Where)
                
            {
                    _Nodeptr cur 
            = _Where._Mynode();
                    
            if (_Cur == cur)
                        _Cur 
            = _Nextnode(cur);
                    
            return _Mybase::erase(_Where);
                }


                
            // 用于安全遍歷
            public:
                iterator find_first()                
            return iterator(_Cur = _Nextnode(_Myhead), this); }
                const_iterator find_first() 
            const    return const_iterator(_Cur = _Nextnode(_Myhead), this); }

                iterator find_next(iterator cur)
                
            {
                    
            if (cur._Mynode() == _Cur)
                        _Cur 
            = _Nextnode(_Cur);
                    
            return iterator(_Cur, this);
                }


                const_iterator find_next(const_iterator cur) 
            const
                
            {
                    
            if (cur._Mynode() == _Cur)
                        _Cur 
            = _Nextnode(_Cur);
                    
            return const_iterator(_Cur, this);
                }

            }
            ;

            posted on 2008-11-15 01:41 PeakGao 閱讀(3385) 評(píng)論(11)  編輯 收藏 引用 所屬分類: C++技術(shù)

            評(píng)論

            # re: 安全的list 2008-11-16 09:40 winsty

            這個(gè)不是線程安全的問題么……  回復(fù)  更多評(píng)論   

            # ????? 2008-11-16 18:45 是什么

            看不懂 是什么哦
            電腦程序
              回復(fù)  更多評(píng)論   

            # re: 安全的list[未登錄] 2008-11-17 10:30 PeakGao

            @是什么
            是這樣的,當(dāng)list的操作很簡單時(shí),遍歷list幾乎沒有什么問題,也可以在遍歷的時(shí)候刪除當(dāng)前節(jié)點(diǎn),如:
            for (std::list<int>::iterator it=list.begin(); it!=list.end();)
            {
            if (條件為真)
            it = list.erase(it); // 刪除當(dāng)前節(jié)點(diǎn)
            else
            ++it;
            }

            但是當(dāng)這個(gè)list不是很簡單的遍歷時(shí),而且刪除的時(shí)候也不是很顯式的在遍歷過程中時(shí),就很容易出問題,如:

            void MapManager::update(...)
            {
            // typedef std::list<Entity*> DisplayList;
            for (DisplayList::iterator it=mDisplayList.begin(); it!=mDisplayList.end();)
            {
            (*it)->update(...);
            }
            }

            但是(*it)->update(...);會(huì)調(diào)用到另一個(gè)模塊中去了,可能會(huì)這樣調(diào)用:
            void Entity::update(...)
            {
            //...
            MapManager->removeEntity(this);
            }

            而removeEntity會(huì)涉及到erase節(jié)點(diǎn):
            void MapManager::removeEntity(Entity* e)
            {
            mDisplayList.remove(e);
            }

            如果Entity的update方法中,發(fā)現(xiàn)自己的生命期已經(jīng)結(jié)束的話,就會(huì)刪除自己,這樣MapManager::update里面就非法了,這是一個(gè)站在磚頭上拿掉磚頭的問題,必定非法。這個(gè)safelist就是為了支持在遍歷列表的過程中能安全的erase任何節(jié)點(diǎn)。

            可能你們沒有碰到該類問題,或者使用list的時(shí)候沒有那么復(fù)雜,所以一時(shí)沒法去了解。  回復(fù)  更多評(píng)論   

            # re: 安全的list 2008-11-17 14:33 不懂

            std::list<int>::iterator itTmp;

            for (std::list<int>::iterator it=list.begin(); it!=list.end();)
            {
            if (條件為真)
            {
            itTmp = it;
            ++itTmp;
            it = list.erase(it); // 刪除當(dāng)前節(jié)點(diǎn)
            it = itTmp;
            }
            else
            ++it;
            }
              回復(fù)  更多評(píng)論   

            # re: 安全的list 2008-11-18 08:38 不懂

            但是當(dāng)這個(gè)list不是很簡單的遍歷時(shí),而且刪除的時(shí)候也不是很顯式的在遍歷過程中時(shí),就很容易出問題  回復(fù)  更多評(píng)論   

            # re: 安全的list 2008-11-18 08:38 不懂

            但是當(dāng)這個(gè)list不是很簡單的遍歷時(shí),而且刪除的時(shí)候也不是很顯式的在遍歷過程中時(shí),就很容易出問題

            如果真有這樣的問題,那就是框架有問題  回復(fù)  更多評(píng)論   

            # re: 安全的list[未登錄] 2008-11-18 08:58 PeakGao

            @不懂
            理論上是這樣,框架徹底的好就沒有問題,但是在游戲更新時(shí),經(jīng)常有生命期結(jié)束的對(duì)象,這樣的對(duì)象需要從地圖上面移除,就涉及到從列表中erase,而生命期結(jié)束是根據(jù)update的調(diào)用進(jìn)行檢測(cè)的。當(dāng)然可以有另一個(gè)辦法,就是將檢測(cè)放到一個(gè)時(shí)鐘里面,而不是在list的遍歷過程中,但是這樣會(huì)需要好多多余的時(shí)鐘。再有一種辦法,就是對(duì)象要移除時(shí),只設(shè)置一個(gè)需要移除的標(biāo)志,在下一輪遍歷前才真正移除。發(fā)現(xiàn)越說越復(fù)雜了,總之,這個(gè)功能就是用于list遍歷很復(fù)雜時(shí),也能安全的工作。你的這幾行,參考我上面的,就一句it=list.erase(it)迭代器不需要臨時(shí)保存的!!
            for (std::list<int>::iterator it=list.begin(); it!=list.end();)
            {
            if (條件為真)
            {
            itTmp = it; // 多余
            ++itTmp; // 多余
            it = list.erase(it); // 刪除當(dāng)前節(jié)點(diǎn)
            it = itTmp; // 多余
            }
            else
            ++it;
            }   回復(fù)  更多評(píng)論   

            # re: 安全的list 2008-11-18 09:29 Jeff Chen

            LZ的情況,我也遇到過,困惑過。當(dāng)我看完jabberd2的代碼后,覺得它的做法比較好。

            方法如下:
            程序每次先遍歷所有的Connection時(shí),無效的Connection將自己移入一個(gè)CloseList中。
            在遍歷所有的Connection后,程序接著清理CloseList里的Connection。

            這樣做的好處,不會(huì)出現(xiàn)LZ這種list“重入”的問題,而且可以靈活處理不需要的對(duì)象。  回復(fù)  更多評(píng)論   

            # re: 安全的list 2008-11-18 17:06 LOGOS

            頂樓上
            mark it & lazy delete

            這樣做在在邏輯上更為完整,相對(duì)于作者直接刪除對(duì)象而言
              回復(fù)  更多評(píng)論   

            # re: 安全的list[未登錄] 2008-11-20 13:35 PeakGao

            @Jeff Chen
            你這種其實(shí)就是我上面說的這個(gè)意思:“再有一種辦法,就是對(duì)象要移除時(shí),只設(shè)置一個(gè)需要移除的標(biāo)志,在下一輪遍歷前才真正移除。”,不過你的說法好像有問題哦,遍歷時(shí)根本不知道是無效的Connection哦,而且不能在遍歷的過程中將節(jié)點(diǎn)移入到另一個(gè)列表,這樣會(huì)掛的  回復(fù)  更多評(píng)論   

            # re: 安全的list(更簡單的用法) 2009-01-08 08:46 canaan

            http://zhgn.vicp.net/boke/200901071529.htm
            List.erase(p)的用法  回復(fù)  更多評(píng)論   

            <2025年5月>
            27282930123
            45678910
            11121314151617
            18192021222324
            25262728293031
            1234567

            導(dǎo)航

            統(tǒng)計(jì)

            常用鏈接

            留言簿(9)

            隨筆分類(67)

            隨筆檔案(65)

            搜索

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

            久久国产精品-久久精品| 香蕉久久夜色精品国产2020| 精品久久久久久中文字幕人妻最新| 欧美日韩精品久久久久| 日产精品久久久久久久| 久久se精品一区精品二区国产| 亚洲午夜精品久久久久久浪潮| 久久SE精品一区二区| 久久成人永久免费播放| 亚洲精品乱码久久久久久中文字幕 | 国产国产成人精品久久| 久久国产成人精品国产成人亚洲| 久久久久亚洲AV无码专区首JN| 69久久精品无码一区二区| 日本国产精品久久| 久久精品人人做人人爽电影| 久久久国产打桩机| 久久午夜综合久久| 国产成人久久精品二区三区| 国产成人精品综合久久久| 亚洲欧美日韩久久精品| 国产日韩欧美久久| www久久久天天com| 久久久久国产精品熟女影院 | 久久se精品一区二区| 无码人妻久久一区二区三区蜜桃| 99久久国产综合精品成人影院| 国产成人精品白浆久久69| 久久精品国产乱子伦| 狠狠色综合网站久久久久久久高清 | 亚洲国产精品综合久久一线| 久久精品亚洲乱码伦伦中文| 亚洲国产精品久久久久久| 青青青国产精品国产精品久久久久| 一本色综合网久久| 久久久久AV综合网成人| 久久久久99精品成人片欧美| 2021少妇久久久久久久久久| 久久精品国产影库免费看| 久久精品综合一区二区三区| 久久精品女人天堂AV麻|