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

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| 国产三区二区一区久久| 一本色道久久加勒比88综合| 欧美国产精品人人做人人爱| 久久综合狠狠综合久久激情| 久久精品最新地址| 久久久国产精彩视频美女艺术照福利| 欧美在线视频一区二区三区| 久久精品五月婷婷| 欧美大片网址| 亚洲人成在线播放| 一区二区三区色| 亚洲欧美一区二区三区极速播放| 午夜精品视频一区| 欧美gay视频激情| 欧美三级电影大全| 国产在线精品二区| 日韩视频中文| 欧美一区二区三区播放老司机| 欧美精品一区二区精品网| 欧美国产视频一区二区| 欧美日韩精品综合在线| 国产一区二区三区四区五区美女 | 久久精品视频亚洲| 免费久久久一本精品久久区| 亚洲美女性视频| 欧美一级午夜免费电影| 欧美不卡在线视频| 国产欧美一区二区三区视频| 日韩亚洲精品电影| 久久久久国产免费免费| 亚洲精品一区二区三区不| 欧美在线一区二区| 国产精品家庭影院| 日韩手机在线导航| 欧美aⅴ一区二区三区视频| 一区二区电影免费在线观看| 久久亚洲精品欧美| 国产九九精品| 亚洲影视在线| 亚洲黄色在线视频| 久久久久亚洲综合| 国产乱码精品一区二区三区忘忧草 | 免费h精品视频在线播放| 日韩视频永久免费观看| 美女成人午夜| 伊人成人在线| 欧美中文在线观看| 亚洲婷婷国产精品电影人久久| 欧美成人黄色小视频| 国产一区av在线| 欧美怡红院视频| 亚洲视频欧美在线| 欧美午夜片欧美片在线观看| 一本到12不卡视频在线dvd| 免费成人黄色av| 欧美在线1区| 国产亚洲欧美一区二区| 欧美一区二区免费观在线| 亚洲免费视频观看| 国产欧美精品久久| 久久精品日产第一区二区三区| 在线亚洲精品| 国产精品日韩在线观看| 香蕉久久夜色精品国产使用方法| 亚洲视频国产视频| 国产精品网站在线观看| 欧美在线视频网站| 久久精品最新地址| 亚洲国产成人久久| 亚洲黄色性网站| 欧美日韩亚洲一区| 亚洲欧美日韩精品久久| 午夜国产精品视频免费体验区| 亚洲伦理自拍| 欧美午夜不卡在线观看免费| 亚洲免费一在线| 亚洲一区黄色| 国产一区二区三区四区老人| 欧美激情国产日韩| 欧美午夜在线视频| 欧美一区二粉嫩精品国产一线天| 午夜精品视频| 91久久精品美女| 一本色道久久综合亚洲精品不 | 欧美成人中文| 欧美福利一区二区| 亚洲午夜av在线| 香蕉久久精品日日躁夜夜躁| 激情五月婷婷综合| 亚洲成人在线视频播放 | 亚洲欧美自拍偷拍| 国产日韩综合| 亚洲国产另类精品专区| 国产精品人成在线观看免费| 蜜桃av噜噜一区二区三区| 欧美ab在线视频| 午夜在线精品偷拍| 欧美69wwwcom| 欧美一区2区三区4区公司二百| 麻豆久久久9性大片| 亚洲欧美韩国| 你懂的网址国产 欧美| 先锋亚洲精品| 欧美精品v日韩精品v韩国精品v | 一区二区在线不卡| 亚洲三级国产| 国内外成人免费视频| 亚洲精品免费一区二区三区| 国产日韩欧美综合一区| 亚洲欧洲视频在线| 狠狠色噜噜狠狠狠狠色吗综合| 亚洲狼人综合| 亚洲国产精品一区在线观看不卡| 亚洲影院免费观看| 亚洲精品久久久蜜桃| 久久成人精品视频| 午夜日韩在线观看| 欧美日韩系列| 亚洲成色777777在线观看影院| 国产视频一区三区| 亚洲一区二区三区涩| 99re热这里只有精品免费视频| 久久国产精品一区二区三区四区| 亚洲视频综合在线| 欧美精品亚洲精品| 亚洲国产导航| 久久综合色88| 久久精品亚洲国产奇米99| 国产精品久久久久久久久久三级| 亚洲成人在线视频播放 | 亚洲人成7777| 久久精品99无色码中文字幕| 亚洲欧美一区二区在线观看| 欧美日韩高清在线观看| 欧美国产丝袜视频| 亚洲高清自拍| 美女精品国产| 亚洲第一精品影视| 亚洲欧洲免费视频| 欧美激情一区在线| 最新高清无码专区| 日韩一级精品| 欧美日韩午夜在线| 亚洲网站在线播放| 香蕉久久夜色精品国产使用方法| 国产精品av久久久久久麻豆网| 亚洲美女av网站| 一区二区高清在线观看| 欧美日韩一区三区四区| 一区二区三区四区精品| 午夜在线视频观看日韩17c| 国产日韩欧美不卡在线| 欧美在线不卡视频| 免费成人高清| 一本一本久久a久久精品综合妖精 一本一本久久a久久精品综合麻豆 | 亚洲午夜久久久久久久久电影院| 一本一本a久久| 国产精品久久久久久久久搜平片| 亚洲视频在线视频| 久久精品成人| 亚洲电影一级黄| 欧美另类久久久品| 亚洲免费综合| 免费不卡视频| 亚洲图色在线| 国产亚洲欧美日韩精品| 免费不卡在线观看| 一区二区不卡在线视频 午夜欧美不卡在 | 亚洲欧美福利一区二区| 国产日韩在线视频| 欧美成人免费一级人片100| 夜夜爽www精品| 久久精品一区二区国产| 欧美另类女人| 久久精品国产久精国产一老狼| 亚洲国产天堂久久国产91| 午夜视频在线观看一区二区| 伊人久久成人| 国产精品乱子久久久久| 麻豆精品视频在线观看| 亚洲自拍另类| 亚洲国产毛片完整版| 久久精品麻豆| 一区二区精品国产| 一色屋精品视频在线看| 国产精品久久久久久久电影| 久久综合国产精品台湾中文娱乐网| av成人毛片| 欧美电影免费观看高清| 久久精品国产精品亚洲精品| 一区二区三区国产精华| 狠狠色综合色综合网络| 欧美午夜精彩| 欧美激情按摩在线| 久久影视精品| 欧美一区二区网站| 亚洲一卡二卡三卡四卡五卡| 91久久精品日日躁夜夜躁国产| 久久亚洲精品一区二区|