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

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>
            欧美韩国一区| 亚洲综合日韩在线| 国内精品视频在线观看| 亚洲国产精品尤物yw在线观看 | 亚洲国产午夜| 久久精品久久综合| 亚洲无线视频| 欧美午夜一区| 一区二区三区精密机械公司| 欧美国产日韩在线| 久久激情五月丁香伊人| 国产精品婷婷| 欧美亚洲日本网站| 亚洲欧美日韩视频二区| 国产精品一区二区三区四区| 亚洲伊人一本大道中文字幕| 日韩一区二区精品| 欧美日韩视频在线观看一区二区三区 | 久久久青草青青国产亚洲免观| 亚洲第一精品电影| 久久一区国产| 亚洲精品日韩一| 亚洲肉体裸体xxxx137| 欧美不卡高清| 中国亚洲黄色| 亚洲系列中文字幕| 国产日韩欧美一区在线| 久久成人这里只有精品| 久久激情久久| 国产精品综合网站| 亚洲黄色成人| 欧美日韩亚洲另类| 亚洲一区二区三区四区五区黄| 日韩视频久久| 国产精品久久久久aaaa樱花| 久久精彩视频| 老司机午夜免费精品视频| 亚洲精品欧美精品| 亚洲一本大道在线| **欧美日韩vr在线| 日韩午夜剧场| 国产一区二区在线观看免费播放| 浪潮色综合久久天堂| 欧美精品v日韩精品v韩国精品v | 亚洲日本欧美| 一个色综合导航| 黄色av日韩| 一本色道久久综合狠狠躁篇的优点| 国产精品爽爽ⅴa在线观看| 久久综合中文色婷婷| 欧美大片第1页| 亚洲一二三四久久| 久久久久久香蕉网| 亚洲婷婷在线| 免费毛片一区二区三区久久久| 一区二区三区视频在线播放| 亚洲欧美日韩综合国产aⅴ| 亚洲国产日韩在线一区模特| 一区二区欧美国产| 亚洲高清在线观看一区| 日韩一级片网址| 亚洲国产精品成人综合| 亚洲欧美日韩爽爽影院| 99re热这里只有精品免费视频| 亚洲网站视频| 亚洲国产精品久久久久婷婷老年| 亚洲国产老妈| 国产欧美日韩综合精品二区| 亚洲国产成人精品视频| 麻豆亚洲精品| 亚洲人成在线免费观看| 国产人成精品一区二区三| 欧美国产精品va在线观看| 国产精品久久久久久久久久久久| 美国成人直播| 国产一区二区三区最好精华液| 夜夜嗨av一区二区三区网页| 亚洲高清av| 欧美一区二区高清| 亚洲影院高清在线| 欧美日产国产成人免费图片| 久久综合色影院| 国产欧美一区二区精品仙草咪 | 亚洲精品孕妇| 美女国产精品| 久久久久99| 国产午夜亚洲精品羞羞网站| 午夜精品久久久99热福利| 亚洲少妇诱惑| 亚洲毛片网站| 乱中年女人伦av一区二区| 久久大逼视频| 国产精品夜夜嗨| 亚洲影视在线播放| 亚洲欧美一区二区在线观看| 欧美sm视频| 老司机精品视频一区二区三区| 国产精品有限公司| 99pao成人国产永久免费视频| 亚洲精品在线观看视频| 欧美成人综合网站| 亚洲激情综合| 在线亚洲欧美专区二区| 欧美涩涩视频| 亚洲免费影视| 欧美一区二区日韩| 国内自拍视频一区二区三区| 久久精品国产亚洲高清剧情介绍| 久久久久欧美精品| 亚洲第一区在线| 欧美激情国产日韩| 一区二区三区产品免费精品久久75| 亚洲一区二区三区激情| 国产精品免费看久久久香蕉| 篠田优中文在线播放第一区| 久久久久久噜噜噜久久久精品| 国产一区二区三区久久悠悠色av | 亚洲国产美女| 欧美日韩成人在线播放| 激情成人综合| 欧美亚洲免费高清在线观看| 国产区欧美区日韩区| 久久视频在线免费观看| 91久久一区二区| 亚洲欧美成aⅴ人在线观看| 国产精品入口麻豆原神| 久久久久免费观看| 亚洲人成绝费网站色www| 亚洲欧美日韩中文播放| 国产一区二区三区日韩欧美| 毛片av中文字幕一区二区| 亚洲精品久久久久中文字幕欢迎你| 亚洲一区二区三区免费在线观看| 国产一区二区三区网站| 欧美黄色大片网站| 午夜伦欧美伦电影理论片| 免费观看在线综合| 午夜精品久久久久99热蜜桃导演| 怡红院精品视频| 国产精品美女久久久久aⅴ国产馆| 亚洲欧美欧美一区二区三区| 亚洲丰满少妇videoshd| 欧美在线网址| 亚洲香蕉伊综合在人在线视看| 黑人极品videos精品欧美裸| 欧美日本一区| 久久蜜桃精品| 亚洲欧美国产日韩中文字幕| 亚洲欧洲日本专区| 麻豆精品在线视频| 久久本道综合色狠狠五月| 99xxxx成人网| 亚洲二区视频在线| 激情综合自拍| 亚洲麻豆av| 在线精品在线| 国产一区二区三区av电影| 欧美.www| 欧美在线视频免费| 在线视频欧美日韩| 欧美成人精品激情在线观看| 先锋影音久久| 亚洲美女av网站| 亚洲国产成人精品女人久久久| 欧美四级在线观看| 欧美成人精品一区| 米奇777超碰欧美日韩亚洲| 欧美在线看片| 亚洲影院一区| 亚洲欧美日韩国产综合精品二区| 欧美在线视频播放| 亚洲视频一二| 一区二区精品国产| 99国产精品国产精品久久 | 亚洲愉拍自拍另类高清精品| 亚洲精品日韩一| 99综合在线| 亚洲一级免费视频| 亚洲一区在线视频| 亚洲欧美日韩国产综合| 亚洲综合日本| 久久aⅴ国产紧身牛仔裤| 久久国产免费看| 久久天堂av综合合色| 老司机一区二区| 欧美不卡视频| 亚洲人体大胆视频| 日韩视频―中文字幕| 日韩视频一区二区在线观看 | 久久久久久**毛片大全| 久热精品视频在线观看| 美女日韩欧美| 欧美另类视频| 国产精品美女久久久久久2018| 国产精品一区二区男女羞羞无遮挡| 国产精品嫩草99a| 国产欧美日韩精品a在线观看| 国产在线拍偷自揄拍精品| 亚洲高清一区二| 午夜视频一区|