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

            loop_in_codes

            低調(diào)做技術(shù)__歡迎移步我的獨(dú)立博客 codemaro.com 微博 kevinlynx

            最近的兩個(gè)問題:less for std::map,靜態(tài)變量初始化順序


            說下最近自己遇到的兩個(gè)值得讓人注意的問題。
            其一是關(guān)于自己給std::map寫less predicate,std::map第三個(gè)參數(shù)是一個(gè)典型的functor。map內(nèi)部將使用
            這個(gè)functor去判定兩個(gè)元素是否相等,默認(rèn)使用的是std::less。但是為什么傳入的是一個(gè)判斷第一個(gè)參數(shù)
            小于第二個(gè)參數(shù)的functor,而不是一個(gè)判斷兩個(gè)參數(shù)是否相等的functor?按照STL文檔的說法,當(dāng)檢查兩
            個(gè)參數(shù)沒有小于也沒有大于的關(guān)系時(shí),就表示兩個(gè)參數(shù)相等。不管怎樣,我遇到了需要自己寫這個(gè)functor
            的需求,于是:

            struct MyLess
            {
                bool operator() ( long left, long right )
                {
                    //...
                }
            };

            DEBUG模式下編譯沒問題,RELEASE模式下卻出現(xiàn)C3848的錯(cuò)誤。這就有點(diǎn)奇怪了,如果確實(shí)存在語法錯(cuò)誤,
            那么DEBUG和RELASE應(yīng)該一樣才對(duì)。查了下MSDN,C3848的錯(cuò)誤是因?yàn)閏onst限定符造成的,如:

            const MyLess pr;
            pr(); // C3848

            于是,在operator()后加上const,就OK了。看了下VC std::map相關(guān)代碼,以為是DEBUG和RELEASE使用了不
            同的代碼造成。但是我始終沒找到不同點(diǎn)。另一方面,就STL內(nèi)部的風(fēng)格來看,應(yīng)該不會(huì)把predicator處理
            成const &之類的東西,全部是value形式的。奇怪了。

            第二個(gè)問題,涉及到靜態(tài)變量。這個(gè)東西給我的印象特別深刻,因?yàn)橐郧叭ヒ患彝馄髴?yīng)聘時(shí)被問到,當(dāng)時(shí)
            覺得那個(gè)LEADER特別厲害。回來后讓我反思,是不是過多地關(guān)注了C++里的花哨,而漏掉了C里的樸素?導(dǎo)致
            我至今對(duì)純C存在偏好。

            說正題,我現(xiàn)在有如下的文件關(guān)系:

            // def.h
            struct Obj
            {
                Obj()
             {
              ObjMgr::AddObj( id, this );
             }
             int id;
            };

            struct ObjMgr
            {
                static void AddObj( int id, Obj *t )
             {
              ObjTable[id] = t;
             }
             static std::map<int, Obj*> ObjTable;
            };

            static Obj _t;

            // ObjMgr.cpp
            #include "def.h"

            static std::map<int, Obj*>::ObjMgr ObjTable;

            // main.cpp
            #include "def.h"

            這里舉的例子可能有點(diǎn)不恰當(dāng),我在一臺(tái)沒有編譯器的機(jī)器上寫的這篇文章。忽略掉這些旁支末節(jié)。我的意思,
            就是想讓Obj自己自動(dòng)向ObjMgr里添加自己。我們都知道靜態(tài)變量將在程序啟動(dòng)時(shí)被初始化,先于main執(zhí)行之前。

            上面代碼有兩個(gè)問題:

            一、
            代碼沒有按照我預(yù)期地執(zhí)行,如果你按照我的意思做個(gè)測試,你的程序甚至在進(jìn)main之前就crash了。我假定你
            用的是VC,因?yàn)槲覜]在其他編譯器上試驗(yàn)過。問題就在于,Obj的構(gòu)造依賴于ObjTable這個(gè)map對(duì)象。在調(diào)試過程
            中我發(fā)現(xiàn),雖然ObjTable擁有了內(nèi)存空間,其this指針有效,但是,map對(duì)象并沒有得到構(gòu)造。我的意思是,Obj
            的構(gòu)造先于ObjTable構(gòu)造(下幾個(gè)斷點(diǎn)即可輕易發(fā)現(xiàn)),那么在執(zhí)行map::operator[]時(shí),就出錯(cuò)了,因?yàn)檫@個(gè)時(shí)候
            map里相關(guān)數(shù)據(jù)還沒準(zhǔn)備好。

            那是否存在某種機(jī)制可以手動(dòng)靜態(tài)變量的初始化順序呢?不知道。我最后怎樣解決這個(gè)問題的?

            二、
            在還沒有想到解決辦法之前(不改變我的設(shè)計(jì)),我發(fā)現(xiàn)了這段代碼的另一個(gè)問題:我在頭文件里定義了靜態(tài)
            變量:static Obj _t; 這有什么問題?想想預(yù)編譯這個(gè)過程即可知道,頭文件在預(yù)編譯階段被文本展開到CPP
            文件里,然后,ObjMgr.cpp和main.cpp文件里都將出現(xiàn)static Obj _t;代碼。也就是說,ObjMgr.obj和main.obj
            里都有一個(gè)文件靜態(tài)變量_t。

            看來,在頭文件里放這個(gè)靜態(tài)變量是肯定不對(duì)的。于是,我將_t移動(dòng)到ObjMgr.cpp里:

            // ObjMgr.cpp
            #include "def.h"

            static std::map<int, Obj*>::ObjMgr ObjTable;
            static Obj _t;

            按照這樣的順序定義后,_t的構(gòu)造居然晚于ObjTable了。也就是說,放置于前面的變量定義,就意味著它將被
            首先構(gòu)造初始化。這樣兩個(gè)問題都解決了。

            但是,誰能保證這一點(diǎn)特性?C標(biāo)準(zhǔn)文檔里?還是VC編譯器自己?

             

             

             


             

            posted on 2008-11-11 17:55 Kevin Lynx 閱讀(7454) 評(píng)論(13)  編輯 收藏 引用 所屬分類: c/c++通用編程模塊架構(gòu)

            評(píng)論

            # re: 最近的兩個(gè)問題:less for std::map,靜態(tài)變量初始化順序 2008-11-11 19:04 空明流轉(zhuǎn)

            沒有保證初始化順序,要用一些模式手工初始化。  回復(fù)  更多評(píng)論   

            # re: 最近的兩個(gè)問題:less for std::map,靜態(tài)變量初始化順序 2008-11-11 19:42 嘯天豬

            第一個(gè)問題:STL要求predicator應(yīng)該是純函數(shù)性質(zhì),不能有狀態(tài)變化;估計(jì)是你的實(shí)現(xiàn)為了強(qiáng)制這一點(diǎn),在模板內(nèi)部做了些手腳吧

            第二個(gè)問題:同一TU內(nèi),non-local static varible按照定義的順序被初始化,這是標(biāo)準(zhǔn)所規(guī)定的  回復(fù)  更多評(píng)論   

            # re: 最近的兩個(gè)問題:less for std::map,靜態(tài)變量初始化順序 2008-11-11 19:57 Xw.Y

            1. 沒想法

            2. 全局的靜態(tài)變量順序沒有保證。偶也吃過苦頭,查文檔無果。
            通常偶都是在main起來后重新初始化靜態(tài)變量。申明用指針而不用實(shí)例。
            你的例子太復(fù)雜了,
            我印象中這樣就有問題(不過我也可能不正確,這種太容易忘記了)
            //somefile.cpp
            static bool gs_initialized = false;

            class A{
            public:
            A(void) { gs_initialized = true; }
            };

            A InstanceA;

            int main(void){
            // gs_initialized true/false不確定
            }

            問下樓上的,TU是指什么?  回復(fù)  更多評(píng)論   

            # re: 最近的兩個(gè)問題:less for std::map,靜態(tài)變量初始化順序 2008-11-12 09:07 Kevin Lynx

            @嘯天豬
            STL predicator不會(huì)要求是純虛函數(shù)性質(zhì),唯一的要求就是這是一個(gè)具有operator()性質(zhì)的東西,普通C函數(shù),重載了operator() 的類均可。我文章里說的問題在于,函數(shù)不是:
            bool operator() ( .... ) const // 需要加上const
            {
            }

            TU是不是編譯單元?如果是標(biāo)準(zhǔn)規(guī)定,哥們可以給我下文檔鏈接不?

            @Xw.Y

            我的問題同你的本質(zhì)是一樣的。

              回復(fù)  更多評(píng)論   

            # re: 最近的兩個(gè)問題:less for std::map,靜態(tài)變量初始化順序 2008-11-12 09:54 浪跡天涯

            感覺有點(diǎn)印象,后來翻翻EffectiveC++.chm,雜項(xiàng)->條款47:

            對(duì)于不同被編譯單元中的非局部靜態(tài)對(duì)象,你一定不希望自己的程序行為依賴于它們的初始化順序,因?yàn)槟銦o法控制這種順序。讓我再重復(fù)一遍:你絕對(duì)無法控制不同被編譯單元中非局部靜態(tài)對(duì)象的初始化順序。

            很自然地想知道,為什么無法控制?

            這是因?yàn)椋_定非局部靜態(tài)對(duì)象初始化的 " 正確" 順序很困難,非常困難,極其困難。即使在它最普通的形式下 ---- 多個(gè)被編譯單元,多個(gè)通過隱式模板實(shí)例化所生成的非局部靜態(tài)對(duì)象(隱式模板實(shí)例化時(shí),它們本身可能都會(huì)產(chǎn)生這樣的問題) ---- 不僅不可能確定正確的初始化順序,往往連找一個(gè)可以確定正確順序的特殊情況都不值得。

            在 "混沌理論" 領(lǐng)域,有一個(gè)原理稱為 "蝴蝶效應(yīng)" 。這條原理聲稱,世界某個(gè)角落的一只蝴蝶拍動(dòng)翅膀,會(huì)對(duì)大氣產(chǎn)生微小的影響,從而導(dǎo)致某個(gè)遙遠(yuǎn)的地方天氣模式的深刻變化。稍微準(zhǔn)確一點(diǎn)來說也就是:對(duì)于某種系統(tǒng),輸入的微小干擾會(huì)導(dǎo)致輸出徹底的變化。

            軟件系統(tǒng)的開發(fā)也表現(xiàn)了自身的 "蝴蝶效應(yīng)"。一些系統(tǒng)對(duì)需求的細(xì)節(jié)高度敏感,需求發(fā)生細(xì)小的變化,實(shí)現(xiàn)系統(tǒng)的難易程度就會(huì)發(fā)生巨大的變化。例如,條款29說明,將一個(gè)隱式轉(zhuǎn)換的要求從 "String到char*" 改為 "String到const char*",就可以將一個(gè)運(yùn)行慢、容易出錯(cuò)的函數(shù)用一個(gè)運(yùn)行快并且安全的函數(shù)來代替。

            確保非局部靜態(tài)對(duì)象在使用前被初始化的問題也和上面一樣,它對(duì)你的實(shí)現(xiàn)細(xì)節(jié)十分敏感。但是,如果你不強(qiáng)求一定要訪問 "非局部靜態(tài)對(duì)象",而愿意訪問具有和非局部靜態(tài)對(duì)象 "相似行為" 的對(duì)象(不存在初始化問題),難題就消失了。取而代之的是一個(gè)很容易解決的問題,甚至稱不上是一個(gè)問題。

            這種技術(shù) ---- 有時(shí)稱為 "單一模式"(譯注:即Singleton pattern,參見 "Design Patterns" 一書)---- 本身很簡單。首先,把每個(gè)非局部靜態(tài)對(duì)象轉(zhuǎn)移到函數(shù)中,聲明它為static。其次,讓函數(shù)返回這個(gè)對(duì)象的引用。這樣,用戶將通過函數(shù)調(diào)用來指明對(duì)象。換句話說,用函數(shù)內(nèi)部的static對(duì)象取代了非局部靜態(tài)對(duì)象。(參見條款M26)

            這個(gè)方法基于這樣的事實(shí):雖然關(guān)于 "非局部" 靜態(tài)對(duì)象什么時(shí)候被初始化,C++幾乎沒有做過說明;但對(duì)于函數(shù)中的靜態(tài)對(duì)象(即,"局部" 靜態(tài)對(duì)象)什么時(shí)候被初始化,C++卻明確指出:它們在函數(shù)調(diào)用過程中初次碰到對(duì)象的定義時(shí)被初始化。所以,如果你不對(duì)非局部靜態(tài)對(duì)象直接訪問,而用返回局部靜態(tài)對(duì)象引用的函數(shù)調(diào)用來代替,就能保證從函數(shù)得到的引用指向的是被初始化了的對(duì)象。這樣做的另一個(gè)好處是,如果這個(gè)模擬非局部靜態(tài)對(duì)象的函數(shù)從沒有被調(diào)用,也就永遠(yuǎn)不會(huì)帶來對(duì)象構(gòu)造和銷毀的開銷;而對(duì)于非局部靜態(tài)對(duì)象來說就沒有這樣的好事。

              回復(fù)  更多評(píng)論   

            # re: 最近的兩個(gè)問題:less for std::map,靜態(tài)變量初始化順序 2008-11-12 13:33 嘯天豬

            1 我的意思是predicatory應(yīng)該像數(shù)學(xué)函數(shù)那樣,不具備狀態(tài)變化,而不是pure virtual 這個(gè)意思

            你的STL實(shí)現(xiàn)為了強(qiáng)制這個(gè)語意,總是使用const predicator object,這樣就只能調(diào)用operator () const,強(qiáng)制predicator在被使用時(shí)無法發(fā)生狀態(tài)變化。

            STL對(duì)predicator的這個(gè)要求是語意上的,而不是語法上的;Effective STL上解釋的挺好的

            http://stl.winterxy.com/html/item_39.html


            2 TU就是編譯單元

            參見 "C++ standard 2003: 3.6.2 Initialization of non-local objects"

            http://d.download.csdn.net/source/216275
              回復(fù)  更多評(píng)論   

            # re: 最近的兩個(gè)問題:less for std::map,靜態(tài)變量初始化順序 2008-11-12 13:45 luke

            對(duì)于靜態(tài)變量的初始化順序問題,在thinking in java 的name control 一章里介紹了兩個(gè)技巧來出來處理這類問題。  回復(fù)  更多評(píng)論   

            # re: 最近的兩個(gè)問題:less for std::map,靜態(tài)變量初始化順序 2008-11-12 13:47 luke

            錯(cuò)了,是thinking in c++  回復(fù)  更多評(píng)論   

            # re: 最近的兩個(gè)問題:less for std::map,靜態(tài)變量初始化順序 2009-06-04 17:56 adie

            1. "另一方面,就STL內(nèi)部的風(fēng)格來看,應(yīng)該不會(huì)把predicator處理
            成const &之類的東西,全部是value形式的。奇怪了。"

            STL 內(nèi)部就是 const & 的,對(duì)模版類型參數(shù)拷貝代價(jià)是未知的,而且拷貝構(gòu)造函數(shù)是否實(shí)現(xiàn)都未知,必須是 const& 的. VC8 的 std::less:

            template<class _Ty>
            struct less
            : public binary_function<_Ty, _Ty, bool>
            { // functor for operator<
            bool operator()(const _Ty& _Left, const _Ty& _Right) const
            { // apply operator< to operands
            return (_Left < _Right);
            }
            };

            2. 不同編譯單元的靜態(tài)變量初始化順序不確定是因?yàn)殒溄悠鞯捻樞驘o法保證,和寫的 makefile 有關(guān). 但在同一個(gè)編譯單元的靜態(tài)變量初始化順序是可以確定的。
              回復(fù)  更多評(píng)論   

            # re: 最近的兩個(gè)問題:less for std::map,靜態(tài)變量初始化順序 2009-06-04 20:28 Kevin Lynx

            @adie
            1.我這里說的predicator,指的是less本身。包括傳給find_if的functor,都被我稱為predicator。STL內(nèi)部保存這種predicator,都是以value的形式保存。既然是value的形式,就不會(huì)存在調(diào)用這個(gè)predicator的operator()必須要求其為bool (*)() const類型的。以前沒搞清楚這個(gè)問題,現(xiàn)在也沒關(guān)注過。
            你舉的例子中,談的是這個(gè)predicator的bool operator()( ...)成員函數(shù)的參數(shù)為const&。對(duì)于less而言,它的這個(gè)operator()的參數(shù)是map內(nèi)部保存的element。無論是從效率還是其他方面,是肯定要const&的。

            2.初始化順序這個(gè)問題,我對(duì)鏈接器細(xì)節(jié)沒怎么關(guān)注過。不過,情況可能真如你所說。謝過。

              回復(fù)  更多評(píng)論   

            # re: 最近的兩個(gè)問題:less for std::map,靜態(tài)變量初始化順序 2009-06-05 10:29 adie

            呵呵,因?yàn)?predicator 是個(gè)模板參數(shù),不存在 const& 的形式,所以理解成了它的參數(shù)了。
            從語義上說,確如嘯天豬所言,要求它為 const 雖然不能保證就滿足要求,的確也是合理的。
            從語法上來說,雖然這個(gè)比較對(duì)象是以 value 的形式保存的,但是使用這個(gè)比較對(duì)象的函數(shù)是 const 的,因此他得到的 this 指針就是 const 的,它的成員 predicator 對(duì)象也就是 const 的了。
            至于 Debug 可以編譯通過確實(shí)是由于 Debug 和 Release 版的代碼不一樣,Release 比較的時(shí)候用的:
            #define _DEBUG_LT_PRED(pred, x, y) pred(x, y)
            Debug 版比較的時(shí)候用的:
            #define _DEBUG_LT_PRED(pred, x, y) _Debug_lt_pred(pred, x, y, __FILEW__, __LINE__)
            可以看到 Debug 版本比較的時(shí)候用了一個(gè)函數(shù),比較對(duì)象作為函數(shù)參數(shù)傳入的時(shí)候進(jìn)行了一次拷貝,拷貝后的對(duì)象沒有 const 了。  回復(fù)  更多評(píng)論   

            # re: 最近的兩個(gè)問題:less for std::map,靜態(tài)變量初始化順序 2009-06-05 10:36 Kevin Lynx

            @adie
            剛正在看vc2005中的xtree找原因。在_Lbound中,確實(shí)是因?yàn)開DEBUG_LT_PRED導(dǎo)致DEBUG和RELEASE使用了不同的代碼。而且確實(shí)是因?yàn)開Lbound是const的才導(dǎo)致this->comp也是const的。但是,在看到你評(píng)論之前我還沒反應(yīng)過來:因?yàn)閠his->comp通過作為函數(shù)參數(shù)而去掉了const修飾,囧。
            起碼真相大白了。3Q
              回復(fù)  更多評(píng)論   

            # re: 最近的兩個(gè)問題:less for std::map,靜態(tài)變量初始化順序 2011-09-21 17:05 pop

            關(guān)于ObjMgr.obj和main.obj里都有一個(gè)文件靜態(tài)變量_t的問題,我想說,既然都是全局的了,為什么還要static呢,難道全局+靜態(tài)這樣定義變量_t不會(huì)覺得有重復(fù)的感覺嗎(靜態(tài)其實(shí)也是為了數(shù)據(jù)共享);,是不是靜態(tài)的全局變量應(yīng)該不提倡這種寫法呢;
            另外,對(duì)于普通的全局變量定義,都會(huì)寫在.cpp內(nèi),然后.h是extern它,還得加上#param once防止重復(fù)包含,才是標(biāo)準(zhǔn)寫法不是?否則,不出現(xiàn)多個(gè)_t才怪~  回復(fù)  更多評(píng)論   

            色综合合久久天天综合绕视看| 久久亚洲高清综合| 精品久久无码中文字幕| 日本久久久久久中文字幕| 91精品国产色综久久| 中文字幕精品久久| 国产精品一区二区久久精品| 久久精品国产只有精品66 | 青青青青久久精品国产h| 国产成人精品久久亚洲高清不卡 | 日本国产精品久久| 97久久精品无码一区二区| 日本国产精品久久| 曰曰摸天天摸人人看久久久| 中文精品99久久国产 | 久久精品三级视频| 久久久一本精品99久久精品66| 久久精品视频91| 亚洲国产精品久久久久婷婷软件| 2019久久久高清456| 精品国产婷婷久久久| AV狠狠色丁香婷婷综合久久| 久久国产欧美日韩精品免费| 国产69精品久久久久9999| 97久久久久人妻精品专区| 一本一本久久aa综合精品 | 亚洲国产精品久久66| 欧美一区二区三区久久综合 | 人妻精品久久无码专区精东影业 | 精品久久久久久久无码| 久久天天躁狠狠躁夜夜2020一| 久久91精品综合国产首页| 91精品国产高清91久久久久久| 久久久久久精品免费看SSS | 亚洲精品乱码久久久久久蜜桃图片 | 久久综合给合久久狠狠狠97色 | 中文字幕无码久久精品青草| 久久久久亚洲精品中文字幕 | 亚洲综合婷婷久久| 91久久成人免费| 国产精品内射久久久久欢欢|