說下最近自己遇到的兩個值得讓人注意的問題。
其一是關(guān)于自己給std::map寫less predicate,std::map第三個參數(shù)是一個典型的functor。map內(nèi)部將使用
這個functor去判定兩個元素是否相等,默認(rèn)使用的是std::less。但是為什么傳入的是一個判斷第一個參數(shù)
小于第二個參數(shù)的functor,而不是一個判斷兩個參數(shù)是否相等的functor?按照STL文檔的說法,當(dāng)檢查兩
個參數(shù)沒有小于也沒有大于的關(guān)系時,就表示兩個參數(shù)相等。不管怎樣,我遇到了需要自己寫這個functor
的需求,于是:
struct MyLess
{
bool operator() ( long left, long right )
{
//...
}
};
DEBUG模式下編譯沒問題,RELEASE模式下卻出現(xiàn)C3848的錯誤。這就有點奇怪了,如果確實存在語法錯誤,
那么DEBUG和RELASE應(yīng)該一樣才對。查了下MSDN,C3848的錯誤是因為const限定符造成的,如:
const MyLess pr;
pr(); // C3848
于是,在operator()后加上const,就OK了。看了下VC std::map相關(guān)代碼,以為是DEBUG和RELEASE使用了不
同的代碼造成。但是我始終沒找到不同點。另一方面,就STL內(nèi)部的風(fēng)格來看,應(yīng)該不會把predicator處理
成const &之類的東西,全部是value形式的。奇怪了。
第二個問題,涉及到靜態(tài)變量。這個東西給我的印象特別深刻,因為以前去一家外企應(yīng)聘時被問到,當(dāng)時
覺得那個LEADER特別厲害。回來后讓我反思,是不是過多地關(guān)注了C++里的花哨,而漏掉了C里的樸素?導(dǎo)致
我至今對純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"
這里舉的例子可能有點不恰當(dāng),我在一臺沒有編譯器的機器上寫的這篇文章。忽略掉這些旁支末節(jié)。我的意思,
就是想讓Obj自己自動向ObjMgr里添加自己。我們都知道靜態(tài)變量將在程序啟動時被初始化,先于main執(zhí)行之前。
上面代碼有兩個問題:
一、
代碼沒有按照我預(yù)期地執(zhí)行,如果你按照我的意思做個測試,你的程序甚至在進main之前就crash了。我假定你
用的是VC,因為我沒在其他編譯器上試驗過。問題就在于,Obj的構(gòu)造依賴于ObjTable這個map對象。在調(diào)試過程
中我發(fā)現(xiàn),雖然ObjTable擁有了內(nèi)存空間,其this指針有效,但是,map對象并沒有得到構(gòu)造。我的意思是,Obj
的構(gòu)造先于ObjTable構(gòu)造(下幾個斷點即可輕易發(fā)現(xiàn)),那么在執(zhí)行map::operator[]時,就出錯了,因為這個時候
map里相關(guān)數(shù)據(jù)還沒準(zhǔn)備好。
那是否存在某種機制可以手動靜態(tài)變量的初始化順序呢?不知道。我最后怎樣解決這個問題的?
二、
在還沒有想到解決辦法之前(不改變我的設(shè)計),我發(fā)現(xiàn)了這段代碼的另一個問題:我在頭文件里定義了靜態(tài)
變量:static Obj _t; 這有什么問題?想想預(yù)編譯這個過程即可知道,頭文件在預(yù)編譯階段被文本展開到CPP
文件里,然后,ObjMgr.cpp和main.cpp文件里都將出現(xiàn)static Obj _t;代碼。也就是說,ObjMgr.obj和main.obj
里都有一個文件靜態(tài)變量_t。
看來,在頭文件里放這個靜態(tài)變量是肯定不對的。于是,我將_t移動到ObjMgr.cpp里:
// ObjMgr.cpp
#include "def.h"
static std::map<int, Obj*>::ObjMgr ObjTable;
static Obj _t;
按照這樣的順序定義后,_t的構(gòu)造居然晚于ObjTable了。也就是說,放置于前面的變量定義,就意味著它將被
首先構(gòu)造初始化。這樣兩個問題都解決了。
但是,誰能保證這一點特性?C標(biāo)準(zhǔn)文檔里?還是VC編譯器自己?