re: loki技法(1).靜態斷言 OwnWaterloo 2010-04-01 22:57
為了讓編譯器輸出的錯誤信息更容易理解一些:
LOKI_STATIC_CHECK(sizeof(char)==1, bad_compiler );
如果斷言失敗, 輸出的就是:
ERROR_bad_compiler 是一個不完全類型的object。
re: 將成員函數作為回調函數 OwnWaterloo 2010-04-01 18:31
@Sanxcoo
gcc下有繼承關系。
msvc下有多繼承關系。
指向成員的指針就可能不僅僅是一個地址。
re: 將成員函數作為回調函數 OwnWaterloo 2010-04-01 17:41
注意, 成員指針并不一定僅僅是地址。
所以最安全的作法是實現一個轉發函數, 而不是去取地址:
void forwarding(void* o, int i, double d)
{
static_cast<C*>(o)->F(i, d);
}
然后將forwarding綁定到一個object上:
C o;
void (*f)(int, double ) = bind(forwarding, &o);
然后將f傳遞給需要回調的地方:
f(1212, 3.26);
等效于:
o.f(1212, 326);
re: 將成員函數作為回調函數 OwnWaterloo 2010-04-01 17:36
取成員指針地址:
template<typename D,typename S>
D cast_union(S src)
{
union
{
S src;
D dst;
} u = {src};
return u.dst;
}
uintptr_t address = cast_union<uintptr_t>(&C::F);
re: 討論:單件模式的優點何在?有無存在的必要? OwnWaterloo 2010-04-01 16:57
@陳梓瀚(vczh)
>> 一大堆lib搞定了,你挑一個正確的就好了。
挑得出來嗎?
你會為VC6用戶生成相應的binary嗎?
客戶使用了-fabi-version 怎么辦?
客戶使用了-mno-align-double又怎么辦?
你要規定用戶所使用的編譯參數? 你能規定用戶使用的編譯參數?
你能確保用戶"僅僅使用你一個人的庫"?
你想得太簡單了。
>> 那么肯定會有些約束的
這些約束會被很不經意的打破。 很難控制住。
因為C++給了程序員太多可以玩, 可以炫的東西。
所謂的"心智包袱"。
>>尺寸特別小,static沒有任何壞處
算了, 你總是把很有爭議的話說得如此絕對, 我還能說你什么呢。
而且我第3次強調了, 我不想討論全局初始化失敗應該怎樣。
你覺得應該怎樣你可以繼續說。
我上面舉的例子, 僅僅是為了說明對"全局的依賴很難避免"。
我覺得已經足夠說明了。
@溪流
如果由使用MIT許可證的代碼衍生:
只要在源代碼中保留原MIT聲明即可。
如果由使用BSD許可證(3條款版本)的代碼衍生:
1. 源代碼形式發布
同MIT
2. 二進制形式發布
發布的同時附帶衍生自的代碼中包含的BSD聲明。
3. 無論以什么形式發布, 原聲明中出現的人名、組織名、公司名不得用于其他用途。
re: 討論:單件模式的優點何在?有無存在的必要? OwnWaterloo 2010-03-31 15:57
@陳梓瀚(vczh)
>>顯然“所有流行編譯器版本”是一個你只需要下載完寫了從vcproj到的makefile生成器以后就自動完成的事情,一勞永逸也,想做當然能做,而且隨時更新。
這只是構建腳本而已。 我說的是不同編譯器產生出的二進制代碼的兼容性。
你能用msvc鏈接到一個mingw生成的二進制庫嗎?
你能用msvc鏈接到前一個crt版本嗎?
>>運行庫版本一律使用static鏈接,因此可以跟你的編譯器版本捆綁在一起。
看吧, 你又"一律", "一定" 什么的了。
這是C++語言本身的問題。 C++的特性太復雜, 而且是一門開放的語言, 所以會有很多二進制上不兼容的特性。
而且C++這門語言本身就會促使開發者使用復雜的設計。
>> 一個程序不可能也不應該同時使用N套平行的GUI庫(嵌套關系除外)
你沒見過而已。 確實有這樣的東西存在。 MFC+WTL+還有一個什么忘記了。
當然, 那東西確實丑陋。
不過已經是這樣子了, 推倒重來的代價公司受不起, 用戶也受不起。
>>main之前的任何異常都不要捕捉,任由崩潰。想log就捕捉了log,log完還是要throw;以便崩潰
再次強調, "需要全局的依賴" 和 "處理全局初始化錯誤" 是兩回事。
re: 道德問題?論new操作失敗后的操作 OwnWaterloo 2010-03-31 14:52
@溪流
這樣很好。 不要悶頭只顧寫代碼; 花一些時間思考。
re: 道德問題?論new操作失敗后的操作 OwnWaterloo 2010-03-30 22:54
>>我需要給 vector(size_t size) 標記上 throw 嗎?如果不標記,使用者怎么知道這里可能會有異常?
不需要, 不標記就是throw all。
new失敗了
1 :讓bad_alloc直接向上拋就是了
為什么不需要大量的try catch?
因為向上拋的過程中會析構棧上的對象, 回滾狀態, 并找到一個處理器。
你會將代碼寫成異常安全的, 是吧?
2: 采用兩段式。
其實就是使用返回狀態代碼的處理方式了。
在某個函數f中, 先構造一個半成品, 在使用之前create或者怎樣。
如果失敗, 就通過狀態碼向f的調用者報告。
f的調用者g又可能向g的調用者繼續報告。
直到找到一個能處理的地方。
這其實和異常是相同的, 只是異常對這些過程是自動的。
re: 道德問題?論new操作失敗后的操作 OwnWaterloo 2010-03-30 22:48
最近很活躍嘛
re: 討論:單件模式的優點何在?有無存在的必要? OwnWaterloo 2010-03-30 22:37
@陳梓瀚(vczh)
>>初始化的時候連內存都申請不了應該直接崩潰,這是最好的辦法。所以這個不是理由。
"申請不了"同"需要依賴內存分配器已初始化" 完全是兩碼事。
你又跑題了。
>>任何庫不應該悄悄啟動線程,除了GUI
這只是"你覺得"應該這樣。
但你馬上又說了一個反例。
3. 我只想說對全局某些服務的依賴是很難避免的。
singleton關我什么事? 我老早不用這種脫了褲子放屁的玩意了。
>>作為一個庫的發行者,要么提供C++代碼,要么提供所有流行編譯器的二進制編譯結果。這才是負責任的。
作為一個二進制庫的發布者, 將庫用C實現并提供C++的header-only的綁定層; 或者發布C++的源代碼。
這才是負責任的。
所有流行編譯器? 你知道什么叫所有流行編譯器么?
編譯器種類×編譯器版本×編譯器運行庫版本×你的庫版本
你覺得你能負這個責, 你就繼續玩吧。
@溪流
是Loki啦:
http://en.wikipedia.org/wiki/Loki_(C%2B%2B)
http://loki-lib.sourceforge.net/配套的《modern c++ design》是目前看過的最高級的C++書……
boost也有scope_exit,是重量級的。
Loki的ScopeGuard依賴"現有的函數", 比如CloseHandle。
注冊之后, 在block退出時, 會調用這個函數。
而boost scope_exit是"就地編寫退出代碼"(調用函數也包括在內)。
當退出時, 會執行這些代碼。
re: 討論:單件模式的優點何在?有無存在的必要? OwnWaterloo 2010-03-30 16:14
@陳梓瀚(vczh)
>>話說回來,只要保持singleton必須在main前構造完畢這個原則的話,就算你singleton的創建互相依賴,也是不需要鎖的。
class evil
{
evil()
{
pthread_create(... );
_beginthreadex( ... );
}
};
如果這個例子確實太邪惡, 別忘了還有可能會碰見進程共享數據。
re: 討論:單件模式的優點何在?有無存在的必要? OwnWaterloo 2010-03-30 16:12
@陳梓瀚(vczh)
>>不管要不要代碼初始化,只要你堅持所有不同的singleton對象都不需要依賴于其他singleton對象來創建那么就沒有問題。如果不行,那么證明設計有錯,或者沒錯但是很難實現,或者沒錯很容易實現但是很容易寫出bug,總之要改。
你說得也太武斷了。 設計有問題?
總有東西的初始化需要申請內存, 能不依賴C heap和C++ free store?
初始化后有部分東西又需要向atexit注冊, 又依賴另一個全局的東西。
初始化失敗, 有部分人喜歡寫log(雖然我不喜歡), 再次依賴全局的東西。
re: 討論:單件模式的優點何在?有無存在的必要? OwnWaterloo 2010-03-30 16:05
@陳梓瀚(vczh)
>>用一種語言去表達一些概念,如果造成不可消除的重復代碼或模式的話,那么應該在可能的情況下更換語言。
只所以要說C:
1. 上面提到了C
2. C++做二進制兼容的東西很煩
而且, 如果不了解C++在初始化靜態對象時做了哪些工作, 就會犯錯。
比如, 很多人都覺得C++靜態對象初始化是線程安全的, 其實是和實現相關的。
大哥, C++有析構函數, 根本不會寫出這種代碼。
而且, 也不需要一個handle一個RAII類, 有范型的Loki::ScopeGuard, 有boost::scope_exit, 愛怎么玩就怎么玩。
C語言, do while(0) 一層就夠了。
注意利用不可能的handle值。
re: 討論:單件模式的優點何在?有無存在的必要? OwnWaterloo 2010-03-29 20:05
@陳梓瀚(vczh)
main之前自動初始化也是需要代碼的。
C++的運行庫會幫忙做這個事情。而C不行。 至少標準C不行。
編譯器提供的DllMain或者 __atrribute__(constructor)啥啥的不算。
所以, C里面init是需要的。
re: 討論:單件模式的優點何在?有無存在的必要? OwnWaterloo 2010-03-29 16:34
@空明流轉
>>都一定是GetXXX()這樣一個自由函數的實現
這沒錯。 而且還要區分2種語意:
1.
xxx_init
...
xxx_get
2.
xxx_get_and_init
第2種語意我不喜歡。
將xxx_get, xxx_init搞成xxx::instance完全是脫了褲子放屁。
本身就是一個free function的事情, 非要搞出個class出來。
@volnet
現在不也這樣么? 如果是按C語法編譯的話。
有辦法按C99語法編譯么?
C89中聲明必須在block的頭部, 然后是語句。
C++中聲明也是一個語句, 所以就沒有這個區別了。
另外, 問問lz:
>>在未開啟編譯器選項為標準C99的情況下,是會編譯出錯的。
msvc怎么開啟標準C99? msvc好像是不支持c99的?
re: vim ctags taglist 入門應用 OwnWaterloo 2010-02-22 00:50
應該是gnumake, 所以搜索規則是GNUMakefile, Makefile, makefile(排名不分先后,因為我不知道……)
make -f filename 啦
其實*nix的軟件學習還是容易, --help便是, 就是不常用就記不住-_-
omnicppcomplete 據說很強大, 不過沒用過。
感覺類似va那種"一邊輸入一邊就會出現某些提示"不太符合vim的insert模式的風格……
ubuntu默認沒有裝vim?
趕緊去學autotools那套東西啦, 還有pkg-config。
你要發布*nix下的軟件,用戶不會關心你編寫代碼的編輯器,而是會關心編譯代碼和管理依賴的腳本……
然后寫點心得出來, 偶坐享其成~
re: Placement new的用法及用途 OwnWaterloo 2010-02-20 16:15
標準使用方法, 在第1步中應該只涉及內存分配行為, 比如使用operator new, operator new[], malloc。
memset也是不必要的。
在第5步中, 應該只涉及內存歸還行為, 比如使用operator delete, operator delete[], free。
re: 靜態庫中全局變量的初始化問題 OwnWaterloo 2010-01-19 12:06
@Kevin Lynx
編譯器根據什么規則來判斷某個沒有被使用的符號可以不必鏈接到binary中?
這個規則我不了解, 可能C++標準有描述, 也可能沒有。
我只是猜想 :
1. 如果某個extern符號沒有被鏈接到binary中, 那將其改為static, 應該也不會被鏈接到binary中。
2. 如果某個static符號沒有被鏈接到binary中, 那將其改為extern, 也許就會被鏈接到binary中。
這就是機會的意思。
btw, 改為extern const 有效么?
re: 靜態庫中全局變量的初始化問題 OwnWaterloo 2010-01-17 23:04
@Kevin Lynx
在C++中, 非local的const對象, 默認是staic鏈接……
a.cpp
int g_i;
雖然g_i也不一定能被添加到最終代碼中, 但機會應該比:
a.cpp
static int g_i; 要大。
re: 鼎嵌杯決賽第二題 模擬Modbus協議 OwnWaterloo 2010-01-17 20:14
@abilitytao
不知道了…… 要有錯, 也應該是uint32_t 沒有定義才對……
float toIEEE754(unsigned x)
{
typedef int constraint[sizeof(unsigned)==sizeof(float)? 1:-1];
union {
unsigned src;
float dst;
} u = x;
return u.dst;
}
re: 靜態庫中全局變量的初始化問題 OwnWaterloo 2010-01-17 20:08
試試在product_a.cpp中, 將:
const bool _local = factory::instance().register( PRODUCT_A_TYPE,...
改為:
extern const bool local_ = factory::instance()...
或者:
namespace {
extern const bool local = ...
}
可能有效,可能無效。
即使有效,依然不能保證local的初始化順序。main之后執行的代碼,可以保證所有產品已經被注冊,main之前沒有保證。
re: 鼎嵌杯決賽第二題 模擬Modbus協議 OwnWaterloo 2010-01-17 00:35
@abilitytao
這個…… 不就是普通的C函數么?
uint32_t x = 0;
float f = 0.0f;
sscanf("420B999A", "%x", &x );
f = toIEEE754(x);
printf("%.1f", f);
34.9
re: 鼎嵌杯決賽第二題 模擬Modbus協議 OwnWaterloo 2010-01-16 21:07
只要知道處理器使用的是IEEE754, 比如i386, 直接:
float toIEEE754(uint32_t x)
{
union {
uint32_t src;
float dst;
} u = x;
return u.dst;
}
即可。
順便說說…… 題目出得很垃圾…… 語言都不通順……
傻了吧唧的……
re: 【歡迎各位留言討論】C++中運算符New的一個疑問 OwnWaterloo 2010-01-14 02:20
1. 在C/C++代碼正確且C/C++實現(編譯器,運行庫)正確的情況下, C/C++語言保證得到正確的結果。
如果出現了錯誤的結果, 可以問why。
是"C/C++代碼正確"這個假設有誤? 還是"C/C++實現正確"這個假設有誤?
2. 如果C/C++代碼本身有某種錯誤, C/C++實現不保證得到正確的結果, 也不保證得到錯誤的結果, 更不保證會報告錯誤的結果。
代碼的錯誤有可能會被隱藏, 到其他時候發作。
這時候, 詢問"為什么沒有出現錯誤", 是不明智的。
C/C++實現沒有義務保證產生一個錯誤。
@mikecheng
你很悲劇,你仔細閱讀的manual中的那個例子是錯的。
re: 與臨時對象的斗爭(下) OwnWaterloo 2009-12-04 00:22
哦…… 原來這種技術叫expression template……
其實我心里一直這么叫它的:operation proxy……
re: 與臨時對象的斗爭(上) OwnWaterloo 2009-12-03 16:40
@空明流轉
上面好像沒說清楚…… 我整理一下……
1. 開發的軟件使用商業許可證。
發布的binary使用的是,比如mingw,生成的。
也發布源代碼。
但發布前使用VC express作移植性測試。
當然,還包括VC使用的工程文件也會發布。
有VC授權的人,可以自己使用VC編譯。
這樣算侵權么?
2. 開發的軟件使用非商業許可證,比如new BSD或LGPL
發布源代碼,VC工程文件。侵權么?
發布VC編譯的binary呢?
re: 與臨時對象的斗爭(上) OwnWaterloo 2009-12-03 16:33
@空明流轉
嗯,謝謝~
如果我只是想用VC的編譯器測試一下可移植性。
但并不發布VC生成的binary。
這樣可以么?
或者,我開發的東西使用的是new BSD或者LGPL之類的許可證,可以使用VC express么?
re: 與臨時對象的斗爭(上) OwnWaterloo 2009-12-03 00:27
@唐風
機器上的vs2005和2008是學校給的…… 據說有個什么政策,學校每年只用付3000元就可以使用大量的正版軟件。
不過…… 我已經畢業了…… 機器上的還沒刪…… 繼續用著……
還去下了一個vc10精簡版…… 這肯定是D版了……
據說vc9有免費的,不含ide。
re: 與臨時對象的斗爭(上) OwnWaterloo 2009-12-02 23:51
@唐風
DB是什么???
對那些保守黨,就任由他們去吧……
讓他們在自己的世界里自娛自樂,一次又一次的發明那屬于自己心中完美輪子。
都復用別人的,他們還怎么好開口向老板要錢啊?
一定要說:stl對我們的項目都是不適合的! —— 以顯得自己的項目很牛逼。
然后追加:所以我們自行開發了xxx! —— 以顯得自己很牛逼。
re: 與臨時對象的斗爭(上) OwnWaterloo 2009-12-02 22:58
lambda,aotu,decltype這些都是很有用的特性,沒它們有時候真的是相當的不方便……
而且,lambda完全可以很簡單的純手工模擬一個。
這種毫無新意的機械復制的事情,本來就應該交給編譯器去做。
編譯器實現lambda表達式是不需要花什么力氣的。
只是解析可能會出現麻煩……
auto、decltype更是容易。
其實編譯器已經實現了它們,只是沒有暴露出來而已。
期待c++0x流行啊……
re: 與臨時對象的斗爭(上) OwnWaterloo 2009-12-02 22:50
gcc新版本也支持了。 gcc4.4.0 的stl已經加上對move的支持了。
沒有右值引用,也可以消除很多臨時變量,只是編程很復雜……
需要使用一些proxy,用來"記錄""操作與操作數",僅僅是"記錄"。
只有當出現操作的"接收者"時,操作才被真正執行,直接在接收者上進行操作了。
當然,有move更好,本來就應該是這樣,對立馬就要消亡的對象,盜取一些資源是很合理的……
只是不知道c++0x要什么時候才能流行起來……
看看現在還有N多用vc6的人…… 無語……
re: 散列3 OwnWaterloo 2009-11-27 23:52
re: 散列3 OwnWaterloo 2009-11-27 23:50
@小羅羅
這…… 那鏈接上不是說已經絕版了嗎?
re: 散列3 OwnWaterloo 2009-11-27 20:56
@小羅羅
只看源碼很枯燥,而且有些細節很難理解。
看這本書吧:《C語言接口與實現:創建可重用軟件的技術》
http://www.china-pub.com/14974里面的arena,思想和CvMemStorage是一樣的"零取整放"。
CvMemStorage比arena多一些功能。
書里將arena的同時,會把內存分配器的一些細節說清楚,這些可能是看源代碼多遍都看不出來的。
反正arena章節也不多……
re: 散列3 OwnWaterloo 2009-11-27 18:34
研究opencv的內存管理? 如果是為了使用opencv,可以去研究。
如果是為了研究內存管理…… opencv的內存管理其實很磋……
當然,opencv可能只是為了開發一個足夠庫自身使用的內存管理與動態數據結構而已。就這個需求來說,opencv是達到了。
但"足夠庫自身使用"不一定就能滿足用戶的所有需求。
而opencv也不提供任何方法讓用戶擴展它的庫。
從這方面來說,opencv是相當的鼠目寸光。
比如opencv提供的CvCapture。其內部是有一個C實現的capture接口與capture工廠。
可是它不將接口定義暴露給用戶。
用戶需要自己的capture時怎么辦? 等著opencv去支持嗎? 那是不可能的。只能自己動手。
這個需求還好, 大不了讓自己的capture返回image(image or matrix),然后丟給opencv去處理就可以了。
image的格式opencv還算厚道,暴露出來了。
用戶如果想要實現得好一些,更capture無關,就需要自己再抽象一個capture接口,然后將opencv的capture包含進去 —— 基本就是將CvCapture的代碼再實現一遍 —— 因為那短視的opencv沒將這個可擴展點暴露出來。
如果用戶不滿意CvMemStorage和CvSeq的行為,哼哼……
必須屈服,除非用戶想自己重寫opencv —— 換句話說,就是放棄opencv。
CvMemStorage實現的是一個"多次取、整體放"的策略。
所有的動態數據結構都將數據存放在CvMemStorage分配的內存上。
沒有單獨釋放數據結構中某個元素的方式,只能釋放整個Storage。
可是opencv沒有定義出一個接口,作為CvMemStorage和CvSeq之間的中間層,而是CvSeq直接使用CvMemStorage。
CvMemStorage本身也不咋嘀。甚至還有一個單次分配大小的上限……
一句話,opencv需要輸出動態數據結構的算法和CvSeq綁死了,CvSeq又和CvMemStorage綁死了,而CvMemStorage又實現得不咋嘀……
你要使用opencv嗎?請忍受CvMemStorage……
相比CvCapture可以繞過去;這個問題幾乎無解。
re: 隨筆:對象思想 VS. 過程思想 OwnWaterloo 2009-11-27 17:37
感覺…… 有點文不對題……
文中的重點在于一個函數應該只完成一件事情。
這"一件事情"如何定義…… 可能把它說成"一個需求"更恰當。
一個函數應該只實現一個需求,這個需求一個整體的,要么不變,要么整體改變,不會只變一部分。
目的還是在于能更好的應對需求變化。
這跟"過程" vs "對象"沒什么關系吧?
re: 函數調用棧初探 OwnWaterloo 2009-11-27 02:29
你本來寫的是【quote】吧? cnblogs確實很偏心,cppblog確實是穿小鞋的……
說正題……
這里的評論里可能有你感興趣的內容:
http://www.cnblogs.com/JeffreyZhao/archive/2009/11/17/linker-loader-library-correction-about-call-stack.html#1704232關于push ebp,frame pointer,call-stack,debugging等。
有點長哦,一直往下看。
哈哈,評論的主角就是這篇文章中提到的RednaxelaFX。
應該是同一個人吧?
re: Void and void pointer OwnWaterloo 2009-11-25 01:11
@zml_cnnk
不知道你具體代碼是怎樣的。
我猜可能是這樣。 一個調用鏈上
1. 一開始是有類型的
2. 到了某個地方,使用了void*去保存任意類型,原來的類型就丟失了。
3. 需要析構,找不到類型了。
要想辦法把類型信息帶著。
舉個標準庫中的例子, 保存指針的容器:
vector<int*> vi;
vector<char*> vc;
vi.push_back( new int );
vc.push_back( new char );
實際上,不需要生成T=int*, T=char*這2套模板的代碼。
void* 就可以保存任意對象的指針。
vector<void*> vi;
vector<void*> vc;
vi.push_back( new int);
vc.push_back( new char );
但這樣就丟失了原來的類型。
取出時,就無法得知正確類型了。
delete vi[0]; // error, delete void*
delete vc[0]; // error, delete void*
所以,這里可以作一個偏特化。
template<typename T> // 對指針類型做偏特化
class vector<T*>
{
vector<void*> c_; // 底層容器
public:
// 轉發給底層容器
push_back(T* p)
{
// 隱式類型轉換,void* 可以保存任意對象指針。
return c_.push_back(p);
}
// 取出
T* operator[](size_type index)
{
void* pv = c_[index]; // c_沒有類型信息
T* p = staic_cast<T*>(pv); // 但這個偏特化模板含有類型信息,還原它
return p; // 返回帶有類型信息的指針。
}
...
};
現在客戶代碼依然這么寫:
vector<int*> vi; // 底層使用vector<void*>
vector<char*> vc;
vi.push_back( new int ); // 轉發函數僅含有一個隱式轉換,不生成代碼
vc.push_back( new char ); // inline展開,直接調用vector<void*>::push_backinline
delete vi[0]; // 調用vector<void*>::operator [](index);
delete vc[0]; // 但類型信息沒有丟失
re: GUI框架:消息檢查者 OwnWaterloo 2009-11-24 00:52
@cexer
【我的想法相反。你說類的靈活性不如函數加數據,但類難道不正是建立在函數和數據之上的一個超強結合體?之所以用C之類的 OP 語言實現模式不如C++這樣的 OO 語言容易,一大原因正是它缺少類的支持。】
是的,類是函數和數據的結合,還加上數據隱藏。
超強到談不上……
我也說了的,對單個object,這3門語言的OO實現確實是方便。
靈活與范化的東西,通常比較難用和不方便。
【
這是你舉例說明的用函數來實現檢查者。你可以嘗試真的用函數來實現消息檢查者,這個 ButtonClickingChecker(WORD id) , xxxChecker( ... ) 函數內部你各自要怎么實現?它既要包含不同的數據,又要包含不同的操作,它們返回完全相同的 message_checker 對象,這個 message_checker 又要怎么實現才能以一已之身完成眾多不同的功能?由于不同參數列表的函數實際上是完全不同的東西,你甚至不能以統一的方式保存它們管理它們。
】
你那個MessageChecker怎么完成以一己之身完成,眾多不同功能的?
同樣可以應用到message_checker 上,兩者是相通的,都是靠結構體中嵌的一個函數指針。
-------- -------- -------- --------
關于那個id,wp,lp,我覺得還不錯。
Windows確實需要將系統與用戶之間使用【一條統一的渠道【來通信。
這條渠道演化到【極端】就是這種形式:
void* (*)(void* all_parameter);
但如果所有消息都需要使用動態內存,就有點浪費。
添加一些其他比較常用的值參數 vs 和一個值參數都不用,就是一種折衷。
完全不用,肯定每次都需要動態內存分配。
值參數多了,又可能在一些情況用不上。
所以,Windows最后選擇了
LRESULT (CALLBACK*)(HWND, UINT, WPARAM, LPARAM);
參數少,直接傳遞,參數多,將某個參數理解為指針……
(此處純猜測……)
所以,迎合WndProc的設計還不錯。
-------- -------- -------- --------
其實我是被這段語法吸引的:
window.onCreated += messageHandler( &::_handleCreated );
window.onCreated += messageHandler ( this,&Window::_handleCreated );
很像boost.signal。
而且真正吸引人的是樓主說它是廉價工人~_~
boost.function如果不用支持bind,可能可以不動用動態存儲。
要支持bind…… 而且不使用動態存儲…… 好像不行……
boost.signal肯定是要動用動態存儲的。
等著樓主這部分的實現了~_~
re: Void and void pointer OwnWaterloo 2009-11-23 18:24
@zml_cnnk
delete操作符有2層意思。 析構和釋放內存。
delete pv的話,無法推斷應該調用什么析構函數。
看你的需求了。
1. 如果真的是需要析構,pv的類型再某個地方丟失了,那必須找回來。
2. 如果不需要析構,而僅僅是為了釋放內存。如果是malloc分配的,那就free;如果是operator new分配的,那就operator delete;一定要配對。
re: GUI框架:消息檢查者 OwnWaterloo 2009-11-23 02:45
想起一個說明限制的更通俗的例子:std::for_each。
它就算一種微型框架。
它完成了遍歷的步驟,同時限制了遍歷的方法—— 用一元函數。
使用for_each時
1. 直接存在現有的一元函數:
vector<void*> m; // memory blocks
for_each(m.begin(), m.end(), free );
2. 可以通過for_each配套提供的一些設施完成工作:
vector<shape*> s;
for_each(s.begin(), s.end(), bind2nd(mem_fun(&s::draw),canvas) );
for_each(s.begin(), s.end(), mem_fun(&s::reset) );
3. 擴展for_each —— 添加更多functor
vector<elem> e;
for_each(e.begin(), e.end(), boost::bind( &e::f, ... ) );
但怎么做,都只是個binder而已。還有一些人做出一些帶有簡單邏輯的functor,然后繼續使用std::for_each,語法丑陋得,我都不知道怎么寫…… 所以這里就不列了…… toplanguage上可以找到不少……
4. 當這些都失效時……
可以說,for_each這個框架在大多數時候都是雞肋。
讓人不得不繞過它的限制(傳遞一元函數),直接寫for循環。
而boost.lambda和C++0x的lambda使得for_each變得實用了不少。所以框架是否實用,很難把握。
說for_each是框架嘛…… 主要是因為它的限制。
但是它規模有點小……也可以很輕易的被丟掉。反正是函數模板,不使用就不會被實例化。這又有類庫的性質。
算是一個不太恰當的例子吧。
框架定義了輪廓線,由程序員去填充顏色。
類庫提供調色板等工具,由程序員去繪制。
另外,傳遞給for_each的一元函數的調用語法是:
f( *first ); 而不是 ((*first).*f)();
也是一個自由函數比成員函數更普適與靈活的例子。
將成員函數以自由函數的語法進行調用:
bind(&c::f)( o, ... );
將自由函數以成員函數語法調用…… 好像要定義一個類……