青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

loop_in_codes

低調做技術__歡迎移步我的獨立博客 codemaro.com 微博 kevinlynx

最近的兩個問題:less for std::map,靜態變量初始化順序


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

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

DEBUG模式下編譯沒問題,RELEASE模式下卻出現C3848的錯誤。這就有點奇怪了,如果確實存在語法錯誤,
那么DEBUG和RELASE應該一樣才對。查了下MSDN,C3848的錯誤是因為const限定符造成的,如:

const MyLess pr;
pr(); // C3848

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

第二個問題,涉及到靜態變量。這個東西給我的印象特別深刻,因為以前去一家外企應聘時被問到,當時
覺得那個LEADER特別厲害。回來后讓我反思,是不是過多地關注了C++里的花哨,而漏掉了C里的樸素?導致
我至今對純C存在偏好。

說正題,我現在有如下的文件關系:

// 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"

這里舉的例子可能有點不恰當,我在一臺沒有編譯器的機器上寫的這篇文章。忽略掉這些旁支末節。我的意思,
就是想讓Obj自己自動向ObjMgr里添加自己。我們都知道靜態變量將在程序啟動時被初始化,先于main執行之前。

上面代碼有兩個問題:

一、
代碼沒有按照我預期地執行,如果你按照我的意思做個測試,你的程序甚至在進main之前就crash了。我假定你
用的是VC,因為我沒在其他編譯器上試驗過。問題就在于,Obj的構造依賴于ObjTable這個map對象。在調試過程
中我發現,雖然ObjTable擁有了內存空間,其this指針有效,但是,map對象并沒有得到構造。我的意思是,Obj
的構造先于ObjTable構造(下幾個斷點即可輕易發現),那么在執行map::operator[]時,就出錯了,因為這個時候
map里相關數據還沒準備好。

那是否存在某種機制可以手動靜態變量的初始化順序呢?不知道。我最后怎樣解決這個問題的?

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

看來,在頭文件里放這個靜態變量是肯定不對的。于是,我將_t移動到ObjMgr.cpp里:

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

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

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

但是,誰能保證這一點特性?C標準文檔里?還是VC編譯器自己?

 

 

 


 

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

評論

# re: 最近的兩個問題:less for std::map,靜態變量初始化順序 2008-11-11 19:04 空明流轉

沒有保證初始化順序,要用一些模式手工初始化。  回復  更多評論   

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

第一個問題:STL要求predicator應該是純函數性質,不能有狀態變化;估計是你的實現為了強制這一點,在模板內部做了些手腳吧

第二個問題:同一TU內,non-local static varible按照定義的順序被初始化,這是標準所規定的  回復  更多評論   

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

1. 沒想法

2. 全局的靜態變量順序沒有保證。偶也吃過苦頭,查文檔無果。
通常偶都是在main起來后重新初始化靜態變量。申明用指針而不用實例。
你的例子太復雜了,
我印象中這樣就有問題(不過我也可能不正確,這種太容易忘記了)
//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是指什么?  回復  更多評論   

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

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

TU是不是編譯單元?如果是標準規定,哥們可以給我下文檔鏈接不?

@Xw.Y

我的問題同你的本質是一樣的。

  回復  更多評論   

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

感覺有點印象,后來翻翻EffectiveC++.chm,雜項->條款47:

對于不同被編譯單元中的非局部靜態對象,你一定不希望自己的程序行為依賴于它們的初始化順序,因為你無法控制這種順序。讓我再重復一遍:你絕對無法控制不同被編譯單元中非局部靜態對象的初始化順序。

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

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

在 "混沌理論" 領域,有一個原理稱為 "蝴蝶效應" 。這條原理聲稱,世界某個角落的一只蝴蝶拍動翅膀,會對大氣產生微小的影響,從而導致某個遙遠的地方天氣模式的深刻變化。稍微準確一點來說也就是:對于某種系統,輸入的微小干擾會導致輸出徹底的變化。

軟件系統的開發也表現了自身的 "蝴蝶效應"。一些系統對需求的細節高度敏感,需求發生細小的變化,實現系統的難易程度就會發生巨大的變化。例如,條款29說明,將一個隱式轉換的要求從 "String到char*" 改為 "String到const char*",就可以將一個運行慢、容易出錯的函數用一個運行快并且安全的函數來代替。

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

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

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

  回復  更多評論   

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

1 我的意思是predicatory應該像數學函數那樣,不具備狀態變化,而不是pure virtual 這個意思

你的STL實現為了強制這個語意,總是使用const predicator object,這樣就只能調用operator () const,強制predicator在被使用時無法發生狀態變化。

STL對predicator的這個要求是語意上的,而不是語法上的;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
  回復  更多評論   

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

對于靜態變量的初始化順序問題,在thinking in java 的name control 一章里介紹了兩個技巧來出來處理這類問題。  回復  更多評論   

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

錯了,是thinking in c++  回復  更多評論   

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

1. "另一方面,就STL內部的風格來看,應該不會把predicator處理
成const &之類的東西,全部是value形式的。奇怪了。"

STL 內部就是 const & 的,對模版類型參數拷貝代價是未知的,而且拷貝構造函數是否實現都未知,必須是 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. 不同編譯單元的靜態變量初始化順序不確定是因為鏈接器的順序無法保證,和寫的 makefile 有關. 但在同一個編譯單元的靜態變量初始化順序是可以確定的。
  回復  更多評論   

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

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

2.初始化順序這個問題,我對鏈接器細節沒怎么關注過。不過,情況可能真如你所說。謝過。

  回復  更多評論   

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

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

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

@adie
剛正在看vc2005中的xtree找原因。在_Lbound中,確實是因為_DEBUG_LT_PRED導致DEBUG和RELEASE使用了不同的代碼。而且確實是因為_Lbound是const的才導致this->comp也是const的。但是,在看到你評論之前我還沒反應過來:因為this->comp通過作為函數參數而去掉了const修飾,囧。
起碼真相大白了。3Q
  回復  更多評論   

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

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

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            在线观看91精品国产入口| 久久精品国产亚洲高清剧情介绍| 欧美成在线观看| 欧美一区影院| 欧美一区二区三区另类| 亚洲在线1234| 性视频1819p久久| 欧美一区二区精品久久911| 亚洲私人影院在线观看| 亚洲专区欧美专区| 欧美一区二区三区在线视频| 久久精品国产69国产精品亚洲| 欧美一级在线视频| 免费日韩成人| 欧美系列一区| 狠狠综合久久av一区二区小说| 最新精品在线| 亚洲欧美中文另类| 欧美四级伦理在线| a91a精品视频在线观看| 亚洲欧美春色| 免费在线看成人av| 欧美日韩在线视频首页| 国产日韩一区| 制服丝袜激情欧洲亚洲| 久久国产精品久久久久久久久久| 欧美jjzz| 亚洲女同在线| 欧美久久久久久蜜桃| 国产日产欧美一区| 亚洲另类自拍| 久久精品盗摄| 亚洲美女色禁图| 欧美在线观看网站| 欧美日韩综合另类| 一区二区三区自拍| 性欧美1819sex性高清| 免费在线成人| 亚洲一级二级在线| 欧美黄色网络| 国产在线精品一区二区中文| 99国产精品视频免费观看| 久久精品国产77777蜜臀 | 激情五月综合色婷婷一区二区| 91久久久亚洲精品| 久久久久久久97| 中文在线资源观看网站视频免费不卡| 久久阴道视频| 激情六月婷婷久久| 欧美影视一区| 亚洲你懂的在线视频| 国产精品久久久久7777婷婷| 亚洲精品网址在线观看| 久久久久国产精品一区| 一区二区激情| 欧美日韩国产欧美日美国产精品| 激情欧美丁香| 美女日韩欧美| 久久久久青草大香线综合精品| 国产日韩欧美日韩大片| 亚洲免费一区二区| 亚洲摸下面视频| 国产精品免费看| 亚洲视频在线观看| 日韩视频在线免费观看| 欧美色一级片| 亚洲一区二区在线观看视频| 日韩视频永久免费| 欧美日韩在线免费视频| 在线亚洲精品| 亚洲视频一区二区免费在线观看| 欧美日在线观看| 亚洲免费小视频| 亚洲欧美一区二区在线观看| 国产精品日韩在线观看| 免播放器亚洲一区| 激情国产一区二区| 久久亚洲高清| 久久高清国产| 在线精品视频免费观看| 久久中文字幕一区二区三区| 久久久久久亚洲精品中文字幕| 伊人成人网在线看| 亚洲国产91| 免费中文日韩| 一区二区三区精密机械公司| 夜夜嗨av一区二区三区四季av| 国产精品成人播放| 久久精品一区二区国产| 久久性天堂网| 亚洲免费av观看| 亚洲在线播放| 亚洲欧洲一区| 亚洲欧美偷拍卡通变态| 亚洲国内自拍| 亚洲一区二区三区高清不卡| 狠狠色狠狠色综合日日tαg | 日韩一级裸体免费视频| 国产色视频一区| 亚洲国产高潮在线观看| 国产精品国产三级国产普通话99| 久久成人精品一区二区三区| 免费久久99精品国产| 亚洲欧美另类在线观看| 狼人天天伊人久久| 欧美一区二区三区在线| 欧美不卡视频| 欧美伊人久久久久久久久影院 | 国产精品毛片大码女人| 久久久最新网址| 国产精品第一区| 欧美成人网在线| 国产麻豆午夜三级精品| 亚洲电影在线免费观看| 国产一区自拍视频| 亚洲校园激情| 一区二区三区视频在线观看| 久久视频免费观看| 久久国产直播| 国产精品igao视频网网址不卡日韩| 欧美3dxxxxhd| 韩国精品久久久999| 午夜精品久久久久久久久久久| 亚洲天堂av在线免费| 欧美精品色网| 亚洲精品欧洲精品| 亚洲人成精品久久久久| 久久综合导航| 欧美成人69av| 伊人成人开心激情综合网| 欧美中文字幕不卡| 欧美一区三区二区在线观看| 欧美吻胸吃奶大尺度电影| 亚洲精品视频二区| 一本综合精品| 欧美一级视频免费在线观看| 99国产一区| 精品不卡视频| 欧美激情第8页| 欧美成人精品三级在线观看| 久久久噜噜噜久久人人看| 国产精品视频免费一区| 日韩天堂在线观看| 99热免费精品在线观看| 欧美国产综合| 91久久久国产精品| 亚洲免费观看高清完整版在线观看熊 | 欧美成人首页| 亚洲激情自拍| 亚洲精品视频一区二区三区| 美女精品视频一区| 欧美激情视频一区二区三区免费| 91久久线看在观草草青青| 欧美国产激情二区三区| 亚洲人成欧美中文字幕| 国产精品99久久久久久久女警| 国产精品www994| 亚洲一级片在线看| 久久九九国产精品怡红院| 在线观看国产日韩| 欧美激情一区三区| 亚洲无线视频| 久久久久免费视频| 亚洲另类自拍| 国产欧美三级| 欧美jizzhd精品欧美巨大免费| 99re6热在线精品视频播放速度| 午夜精品福利在线观看| 黄色资源网久久资源365| 欧美寡妇偷汉性猛交| 这里是久久伊人| 欧美福利精品| 羞羞色国产精品| 亚洲麻豆国产自偷在线| 国产手机视频一区二区| 免费观看成人网| 亚洲天堂av综合网| 免费在线国产精品| 亚洲男人的天堂在线aⅴ视频| 韩国一区二区在线观看| 欧美日韩午夜视频在线观看| 久久久久.com| 亚洲视频免费在线| 免费在线成人av| 欧美一区二区三区婷婷月色 | 久久久久综合网| 一区二区三区导航| 精品999在线播放| 国产精品久99| 免费在线看一区| 久久久999精品免费| 一本久道久久综合狠狠爱| 女人香蕉久久**毛片精品| 欧美一区二区三区另类| 亚洲视频观看| 亚洲欧洲三级电影| 久久精彩免费视频| 国产精品欧美日韩一区二区| 欧美成年人网站| 亚洲欧美日韩精品|