• <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>

            3d Game Walkman

            3d圖形渲染,網(wǎng)絡(luò)引擎 — tonykee's Blog
            隨筆 - 45, 文章 - 0, 評(píng)論 - 309, 引用 - 0
            數(shù)據(jù)加載中……

            今天找到一個(gè)不得不用deque的理由

            過(guò)去總以為vector和deque差不多,效率方面deque和vector接近,那干脆用效率高的vector好了。
            但我忽略了另一方,一個(gè)事務(wù)存在就有它的理由,今天找到程序里面隱藏的bug給了我不得不用deque的理由,
            deque和vector的結(jié)構(gòu)很類(lèi)似,但它是多段連續(xù)空間,如果vector空間不夠的時(shí)候,要重新分配空間,并把所有的數(shù)據(jù)復(fù)制到新的空間中去,
            deque不會(huì)這么做,它會(huì)去另外開(kāi)辟一塊連續(xù)空間去存放數(shù)據(jù),所以存儲(chǔ)效率方面deque高于vector,但deque又不同于鏈表,它可以說(shuō)是順序存儲(chǔ)結(jié)構(gòu)和鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu)的一個(gè)折中方案把,今天我寫(xiě)了段代碼,是這樣的結(jié)構(gòu)

            vector<SerializedEntity> archiveEntities; //也許你要問(wèn)問(wèn)什么不用vector<SerializedEntity*>,我這里比較特別,因?yàn)橐x寫(xiě)磁盤(pán)的數(shù)據(jù),序列化存儲(chǔ)                                            //回避了指針的數(shù)據(jù)讀寫(xiě)方式,所以用的vector<SerializedEntity>
            那么:Entity * ent = &archive[0];          //看似沒(méi)問(wèn)題,其實(shí)里面暗藏殺機(jī)
            這個(gè)archiveEntities 如果不改變是沒(méi)有問(wèn)題,但如果序列集又動(dòng)態(tài)添加了數(shù)據(jù),恰好沒(méi)有預(yù)留空間,那么將導(dǎo)致整個(gè)集合重新分配連續(xù)空間了,所以那個(gè)引用也將“失效了”,這讓我很頭疼,這個(gè)時(shí)候讓我想起了deque,它真的很棒,不會(huì)去重整空間,需要的時(shí)候再開(kāi)辟其他連續(xù)的空間,雖然讀的效率降低了,但
            這點(diǎn)損失對(duì)于我的程序基本可以忽略不計(jì)的,IO數(shù)據(jù)本身就很少去遍歷訪問(wèn),卻能給程序很好的去“引用”,不用擔(dān)心引用失效的情況,這方面deque確實(shí)是個(gè)很好的選擇
            找到一篇文章與大家分享一下,也是應(yīng)證我的觀點(diǎn)的:

            operator[]

              operator[] 是指通過(guò)下標(biāo)取數(shù)據(jù)。顯然 list 的復(fù)雜度為O(N),非常慢。而 vector、deque 均為 O(1)。讓我們想象下 deque::operator[] 的實(shí)現(xiàn):

             

             _E deque::operator[](int i)
            {
              return m_storage[i/BlockSize][i%BlockSize];
            } 

             

              可以看出,deque 只比 vector 多了一次內(nèi)存訪問(wèn)。

              空間性能分析

              push_back

              vector

              很不幸,如果 vector 采用 N*2 的內(nèi)存增長(zhǎng)模型(通常如此),那么在最差的情況下,空間復(fù)雜度就是 2*N ,最好的情況下為 N(所有的內(nèi)存都用上了)。平均來(lái)講,空間復(fù)雜度為 1.5*N .也就是說(shuō),通常差不多有一半的內(nèi)存是被浪費(fèi)的。

              list

              list 的空間浪費(fèi)與 vector 相比不遑多讓。它的空間復(fù)雜度為 (1 + sizeof(pointer)*2/sizeof(_E))*N.如果我們讓 list 存儲(chǔ)的元素為 pointer(即 _E = pointer),那么空間復(fù)雜度為 3*N,比 vector 還浪費(fèi)。

              deque

              deque 的最差情況下的空間復(fù)雜度為 N + sizeof(pointer)*2*N/(BlockSize*sizeof(_E))(這里假設(shè)vector也采用 2*N 增長(zhǎng)模型,平均復(fù)雜度則將式中2改為1.5即可)。如果我們保存的元素為 pointer(即 _E = pointer),并且BlockSize取512,那么空間復(fù)雜度為 N + N/256.也就是說(shuō)最差情況下只浪費(fèi)了 N/256 的內(nèi)存。

              deque的其他特性

              元素地址不變

              由于 deque 并不進(jìn)行數(shù)據(jù)搬移,帶來(lái)一個(gè)有意思的特性,就是 deque 的元素地址在只有 push_back/push_front,沒(méi)有 insert/erase 時(shí),可保持元素地址不變。

              需要注意的是,vector 并不具備這樣的特性。如下的代碼是不合法的:

             

            std::vector<int> vec;
            ...
            int& elem = vec[i];
            vec.push_back(100);
            elem = 99; // error: can't access elem since vec was changed! 

             

              由于取得 elem 之后存在 push_back 操作,所獲得的元素地址(&elem)可能會(huì)由于內(nèi)存搬移而失效。但是如果我們將容器換為 std::deque,則這個(gè)代碼不會(huì)有任何問(wèn)題。

             

             std::deque<int> dq;
            ...
            int& elem = dq[i];
            dq.push_back(100);
            elem = 99; // ok! 

             

              另外需要注意的是,元素地址不變,并不代表 iterator 不變,如下的代碼 deque 并不支持:

             

            std::deque<int> dq;
            ...
            std::deque<int>::iterator it = dq.begin() + i;
            dq.push_back(100);
            *it = 99; // error: can't access iterator since deque was changed!

             

              結(jié)論

              通過(guò) vector, list, deque 的時(shí)間、空間性能對(duì)比,我們可以看出,應(yīng)該提倡盡可能使用 deque 這個(gè)容器。特別是,如果要承受海量數(shù)據(jù),deque 是最合適的人選了。


            posted on 2009-05-24 13:25 李侃 閱讀(8296) 評(píng)論(15)  編輯 收藏 引用 所屬分類(lèi): 雜談

            評(píng)論

            # re: 今天找到一個(gè)不得不用deque的理由[未登錄](méi)  回復(fù)  更多評(píng)論   

            只能說(shuō)你對(duì)vector沒(méi)有認(rèn)識(shí)清楚而以,一般也都使用iterator
            2009-05-24 13:36 | 關(guān)中刀客

            # re: 今天找到一個(gè)不得不用deque的理由  回復(fù)  更多評(píng)論   

            我現(xiàn)在討論的不是迭代,任何集合都能迭代,光用一個(gè)iterator去遍歷,任何集合都沒(méi)有差別了。那一個(gè)vector就夠了還要list和deque做什么?

            我現(xiàn)在討論的是它們的內(nèi)部結(jié)構(gòu)的差別,根據(jù)不同的場(chǎng)景而要用出這些集合的差別才是真道理,樓上看清楚,我現(xiàn)在就是想在外部指針去引用集合內(nèi)部的元素,就是不想每次訪問(wèn)的時(shí)候都去迭代,集合如果只增不減的情況下,用deque是穩(wěn)定的,而vector是不穩(wěn)定的,vector存在空間重排,deque不存在空間重排,這是我要闡述的觀點(diǎn)
            2009-05-24 14:01 | 李侃

            # re: 今天找到一個(gè)不得不用deque的理由  回復(fù)  更多評(píng)論   

            用deque是穩(wěn)定的
            2009-05-24 15:38 | 九久讀書(shū)人

            # re: 今天找到一個(gè)不得不用deque的理由  回復(fù)  更多評(píng)論   

            我試了試,似乎erase中間的元素以后,各元素的地址依然穩(wěn)定,vc自帶的的deque 是這樣的,不知道其他版本的deque會(huì)不會(huì)也是這樣?

            我已經(jīng)深深的愛(ài)上deque了 ^^
            2009-05-24 15:52 | 李侃

            # re: 今天找到一個(gè)不得不用deque的理由  回復(fù)  更多評(píng)論   

            std::deque<int> dq;
            ...
            int& elem = dq[i];
            dq.push_back(100);
            elem = 99; // ok!

            這樣的代碼對(duì)deque即使正確也還是不要用吧。
            2009-05-24 16:55 | 阿淡

            # re: 今天找到一個(gè)不得不用deque的理由  回復(fù)  更多評(píng)論   

            后面的部分是我摘錄網(wǎng)上的文章,覺(jué)得好像也沒(méi)什么不妥
            當(dāng)然了如果元素被移除了,這樣去訪問(wèn)那會(huì)是危險(xiǎn)的。
            2009-05-24 17:32 | 李侃

            # re: 今天找到一個(gè)不得不用deque的理由  回復(fù)  更多評(píng)論   

            個(gè)人意見(jiàn)是,不要直接引用容器內(nèi)的元素地址,特別是長(zhǎng)期引用
            就算你知道自己在做什么,別人也不知道
            2009-05-24 18:01 | LOGOS

            # re: 今天找到一個(gè)不得不用deque的理由  回復(fù)  更多評(píng)論   

            依賴(lài)于一個(gè)容器是否分配內(nèi)存本身就是你的問(wèn)題,不是該不該vector還是queue的問(wèn)題。如果想避免分配內(nèi)存帶來(lái)的問(wèn)題,請(qǐng)用vector<shared_ptr<OBJ>>。
            2009-05-24 21:25 | 陳梓瀚(vczh)

            # re: 今天找到一個(gè)不得不用deque的理由  回復(fù)  更多評(píng)論   

            我明白,如果是vector<Entity*>的方式,根本不用去討論該去用vector還是queue,重排就重排了,指針不會(huì)變
            但如果是vector<Entity> 的形式情況就不同了

            這樣的類(lèi)別的集合確實(shí)就不該直接去引用集合中元素的地址,這不是一個(gè)好的習(xí)慣。

            主要是:我的序列化存儲(chǔ)層只能支持 集合<entity>的形式
            不支持 集合<Entity*>的形式,想引用從文件讀取的集合數(shù)據(jù)又不想做太多的拷貝,迫于無(wú)賴(lài)。

            只好回頭再想想看有沒(méi)有更好的折中方案了。

            2009-05-24 22:34 | 李侃

            # re: 今天找到一個(gè)不得不用deque的理由  回復(fù)  更多評(píng)論   

            不想拷貝又不想自己釋放,用智能指針。
            2009-05-25 10:28 | 陳梓瀚(vczh)

            # re: 今天找到一個(gè)不得不用deque的理由  回復(fù)  更多評(píng)論   

            deque 不能 memcpy
            2009-05-26 21:21 | lovelypig

            # re: 今天找到一個(gè)不得不用deque的理由  回復(fù)  更多評(píng)論   

            STL只是一份標(biāo)準(zhǔn)還不是實(shí)現(xiàn),作為vector來(lái)講,它設(shè)計(jì)目標(biāo)應(yīng)該是作為一個(gè)大小伸縮的數(shù)組,比如&v[0]可以當(dāng)作一個(gè)數(shù)組的指針(如果!v.empty()的話),而deque則不行;deque為了能夠以常數(shù)時(shí)間在順序容器的頭部及尾部進(jìn)行push操作而設(shè)計(jì)的,但這個(gè)設(shè)計(jì)的代價(jià)通常很大,應(yīng)該并不是你所想像的二維數(shù)組的形式,比如SGI的deque設(shè)計(jì)就采用了一種類(lèi)似于文件系統(tǒng)中二級(jí)表的方式,其直接結(jié)果就是迭代器操作的代價(jià)很高。現(xiàn)實(shí)程序中你會(huì)發(fā)現(xiàn)很少有人會(huì)用deque,這固然有書(shū)中介紹比較少的原因,但也與其操作代價(jià)較高是分不開(kāi)的。
            我的意見(jiàn)是,除非不得以,否則使用vector而不要用deque;
            你的這種情況,我建議你可以自己寫(xiě)一個(gè)容器,那怕是用memove,通常也會(huì)比std::vector快很多的
            2009-08-09 19:58 | 李現(xiàn)民

            # re: 今天找到一個(gè)不得不用deque的理由  回復(fù)  更多評(píng)論   

            deque用的不當(dāng),會(huì)造成內(nèi)存急劇消耗!
            2009-09-25 20:39 |

            # re: 今天找到一個(gè)不得不用deque的理由  回復(fù)  更多評(píng)論   

            本來(lái)就是各有所長(zhǎng)的設(shè)計(jì),vector設(shè)計(jì)規(guī)范就是連續(xù),引用元素說(shuō)得清清楚楚就是即時(shí)有效,不能緩存,你就要違背規(guī)范使用,還要說(shuō)它不好,那是你愚蠢還是它不對(duì)呢?
            各種容器就是為了滿足不同需求設(shè)計(jì)的,各有所長(zhǎng)各取所需,但不要說(shuō)一個(gè)取代另一個(gè)的蠢話,如果你覺(jué)得要取代了,說(shuō)明你還認(rèn)識(shí)不夠,也說(shuō)明你起初選擇的時(shí)候是愚蠢的。
            2012-05-10 13:07 | oldworm

            # re: 今天找到一個(gè)不得不用deque的理由[未登錄](méi)  回復(fù)  更多評(píng)論   

            @李侃
            STL用迭代器隱藏了線性容器間的區(qū)別,但這不代表因此各容器就沒(méi)區(qū)別吧?
            每個(gè)容器都有自己的特點(diǎn),不同應(yīng)用場(chǎng)合性能是有差異的,所以才提供這么多線性表容器吧?
            遍歷STL線性表還是用迭代器,C語(yǔ)法和C++語(yǔ)法混合起來(lái)用是不安全的。
            2012-07-06 14:27 | Sine
            久久99精品久久久久婷婷| 久久免费大片| 青青青青久久精品国产| 久久夜色撩人精品国产小说| 久久久久99这里有精品10 | 嫩草影院久久国产精品| 国内精品久久久久久久影视麻豆| 国内精品久久久久影院薰衣草 | 久久久久久国产精品美女| 国产99久久久国产精品小说| 2021少妇久久久久久久久久| 思思久久精品在热线热| 日本道色综合久久影院| 亚洲级αV无码毛片久久精品| 精品无码久久久久久久久久| 久久久久亚洲AV片无码下载蜜桃| 久久久WWW成人| 亚洲国产成人久久综合一| 色综合久久综合中文综合网| 看全色黄大色大片免费久久久 | 久久久综合香蕉尹人综合网| 久久精品国产精品青草| 久久亚洲精品成人AV| 久久人人添人人爽添人人片牛牛| Xx性欧美肥妇精品久久久久久| 久久久久亚洲AV成人片 | 亚洲一区二区三区日本久久九| 中文字幕人妻色偷偷久久| 天天做夜夜做久久做狠狠| 国产精品永久久久久久久久久| 成人国内精品久久久久影院| 久久A级毛片免费观看| 亚洲欧美成人综合久久久 | 9999国产精品欧美久久久久久| 国产精品美女久久久久久2018| 亚洲午夜久久久久久久久久| 国产成年无码久久久免费| 久久综合久久美利坚合众国| 中文成人久久久久影院免费观看| 久久受www免费人成_看片中文| 久久SE精品一区二区|