re: C++ 下 Function 對象的實現(上) OwnWaterloo 2011-01-19 00:47
@溪流
template<typename R>
R call( R (*f)() ) { return f(); }
void __cdecl f() { printf("cdecl\n"); }
void __stdcall g() { printf("stdcall\n"); }
VC8默認情況: call(f) 是可以的, 而 call(g)不行。
因為 call 中的 f 參數沒有指定調用約定。
如果顯式使用 /Gr , 那就call(f)不行, call(g) 可以。
如果使用重載:
template<typename R>
R call( R ( __cdecl *f)() ) { return f(); }
template<typename R>
R call( R ( __stdcall *f)() ) { return f(); }
兩者都可以, 但在g++下, 只要兩者被同時使用, 就是重定義。
re: C++ 下 Function 對象的實現(上) OwnWaterloo 2011-01-19 00:35
@溪流
你會C++還怕C么……
說是教, 也就是以前的死黨指點指點。
都是灰?;A的東西……
re: C++ 下 Function 對象的實現(上) OwnWaterloo 2011-01-19 00:34
@溪流
嗯, 理想是一回事。 有時候還是得向現實屈服……
作為個人的話, 還是可以學學python(perl, ruby) 什么的, 日常編程工作就可以擺脫C/C++了……
re: C++ 下 Function 對象的實現(上) OwnWaterloo 2011-01-19 00:31
@溪流
嗯嗯, 這個確實符合破窗效應。
但15個api與45、 75個api應該用什么效應解釋呢?
反正就我的感覺, 15個會很有耐心的去看; 而45個就沒耐心了; 75個就絕對不想去看了, 并給自己一個心理安慰:這玩意太復雜, 沒設計好……
re: C++ 下 Function 對象的實現(上) OwnWaterloo 2011-01-19 00:29
@溪流
>> 前兩天我在猶豫框架要不要幫用戶解析 WPARAM、LPARAM,你的例子讓我堅定了想法,解析之!
解析WPARAM和LPARAM確實無比無比蛋疼啊……
當然, 最初的那些C程序員也不是沒辦法了, 有個 windowx.h 里面的宏有一些幫助。
我也覺得, 作為一個有責任的庫, 應該做之。
如果能提供沒有解析的原始層次, 供那些有經驗的程序員使用, 似乎也可以?
似乎程序員都有實現gui的沖動?
我也沖動過的…… 但就是被WPARAM, LPARAM擊敗了……
本想以此當作熟悉各種消息的方式, 最終還是沒堅持下來……
沒毅力的人飄過……
re: C++ 下 Function 對象的實現(上) OwnWaterloo 2011-01-19 00:25
@溪流
>> 但一般實現代價一般很小的情況下才會出現這種沖動,想要順手做了。
以前是不管代價如何就很沖動去順手了……
現在想來……
也算是練手吧……
re: C++ 下 Function 對象的實現(上) OwnWaterloo 2011-01-19 00:22
@溪流
貌似你誤會了。
cexer所說的應該是這個情況:
比如需要實現bind(或者是別的功能, 這個不是重點, 只是用于舉例)。
重點是: 庫的用戶會用不同的調用約定的函數傳入。
還是上面的偽代碼:
binder bind( f , arg ) { ... }
R0 __cdecl F0_of_client ( ... );
R1 __stdcall F1_of_client ( ... );
bind(F0_of_client, ... );
bind(F1_of_client, ... );
只有兩者之一會成功。
re: C++ 下 Function 對象的實現(上) OwnWaterloo 2011-01-18 19:39
@yrj
感謝~
其實我困惑的不是"如何實現", 而是"是否需要在C++中實現"。
re: C++ 下 Function 對象的實現(上) OwnWaterloo 2011-01-18 19:37
舉個實際例子 (我就一話癆……) :
最近在教人C語言……
條件包含部分: #if, #elif, #else, #endif, defined 就完全ok了。
所有功能都可以實現。
但C語言還提供了 #ifdef, #ifndef…… 而且人們通常用的就是這個方便的接口……
而且很多時候連#elif, #else都沒有 —— 比如頭文件保護符, 我就是在給別人解釋這個事情。
為什么有#ifdef, #ifndef后, 還要有 #if 與 defined?
若不給初學者解釋 #elif , 是肯定理解不了的。
如果C語言一開始就只為條件包含提供一種方法: #if, #elif, #else, #endif, defined。
大家也就只能這么寫。
那介紹頭文件保護符時, 就先介紹#if, defined, #endif就完了, 暫時不需要牽扯出其他部分, 其他部分可以慢慢了解。
人腦沒法一下子容納太多信息的。
再聲明一下, 以上都是個人觀點, 話癆犯了, 聊聊天而已。
完全沒有"其他人也必須這樣", "這就是事實"的意思……
re: C++ 下 Function 對象的實現(上) OwnWaterloo 2011-01-18 19:24
@cexer
同時, 我還發現C++程序員很容易產生一種傾向:
嗯, 我要設計一個程序庫, 這個庫很smart, 無論怎么使用, 都是可以的。
想怎么用, 就怎么用 —— 以前我也是這樣想的。
就舉這個帖里出現的一個例子: 某處理器需要一個返回值。 是否可以讓程序員在需要默認返回時, 編寫一個返回void的處理器?
就我個人而言 ( 僅僅是個人的看法, 與技術無關了, 兩者都是對的), 類似WTL那樣也是"完全可用"的。
... frame work ...
case WM_XXX :
R result = default_result;
user_handler(&result, ... );
return result;
簽名必須寫為:
(R* response, ... ); // 其實是個引用, 只是指針的話, 上面的frame work中的代碼意圖更明顯。
"有且僅有這一種做法" , 沒有第二選項。
若用戶不關心, 不去修改response的值即可。
其實我也覺得傳出參數是很難看的設計。
但它可工作, 也可以避免去編寫一堆meta programming 代碼, 而且這堆代碼可能又需要同C++的各種陰暗作斗爭。
例如boost, 若不需要"照顧" 這么多編譯器的話, 其實代碼還是可讀的。
但需要照顧這么多編譯器, 那無數的workaround, 使得代碼變得……
不是天書也是爛泥……
"嗯, T是一個原始指針可以, 當它是個smart pointer時也應該要被支持"。
很多時候, C++ 程序員不是去考慮這種需求是否存在, 實現這種需求的復雜度如何, 維護代價如何。
僅僅是因為他們能, 所以他們就要這樣做……
其實有時候, 這些需求僅僅是美學上的, 而不是技術上的。
比如上面那個返回值的例子。
再比如:
f(char const* s, ... ); // primary function
f(std::string const& s, ... ) { return f(s.c_str(), ...); }
f(CString const& s, ... ) { return f(static_cast<char const*>(s), ...); }
...
如果不要后兩者, 任何工作依然可以完成。
后兩者僅僅是提供一種方便, 而不是"核心"接口。
也不是說這種方便不好…… 我的觀點是一定需要有某種方式告之用戶, 哪部分是核心接口。
用戶優先去掌握這部分, 然后整個庫的功能他就可以完全掌握了。
其他的, 學得越多, 使用越方便。
否則, 若沒有這種通告, 一個f不要緊, 若全體函數都這樣搞, 就會增加學習成本。
本來15個核心函數, 如果擴展為45個, 75個, 就不僅僅是量上的變化, 而是質上的變化 —— 讓人失去耐心。
這同為什么要抑制warning一樣, 不是說不可以產生warning, 而是說當warning多到一定程度時, 會超過人的處理極限, 會不自覺的將他們全體忽略掉。
所以發現warning就要干掉, 讓新的warning能引起人注意。
至于通告方式…… 感覺手寫文檔是最靠譜的……
docxgen 什么的…… 產生的文檔太死氣沉沉, 無法感受到當中的輕重緩急。
re: C++ 下 Function 對象的實現(上) OwnWaterloo 2011-01-18 18:58
@cexer
來說一個具體的C++問題吧, 就是這個:
>> 你還需要考慮調用約定的問題,因為 __stdcall,__cdecl,__fastcall的不同,都會使函數簽名不同。有多少種調用約定,functor的綁定函數的數量就需要乘以多少,這是個體力活,可以用預處理元和文件包含來減少體力消耗。
絕對的體力活??! 干過一次絕對不想干第二次……
而且, 你有試過g++么?
g++中這問題很麻煩。
函數重載目前是通過mangling實現的, 而g++對一個函數(free or member)指針類型的mangling只包含普通的signature, 不包含調用約定。
偽代碼:
binder bind( __cdecl f, arg )
binder bind( __stdcall f, arg )
倆f在g++中是不同類型, boost::is_same是false。
但這倆bind函數"不構成重載" , 是bind的重復定義……
原因就是上面提到的, f被mangling時, 它的調用約定信息被忽略了。
倆bind最終產生的符號是相同的。
用C++, 就要和這些許多細枝末節的問題作斗爭……
懶了…… 想逃避之……
re: C++ 下 Function 對象的實現(上) OwnWaterloo 2011-01-18 18:51
@cexer
>> 同時支持靜態和動態的映射方式,關鍵是庫要實現得好,在沒有使用動態映射的時候,這個動態映射的功能就好像不存在一樣,這樣大多數時候既能夠享受空間優勢,在需要的時候又能發揮它的動態優勢。免得用戶要在在空間優勢和靈活性之間做出痛苦的選擇。
說得我口水都流了…… (其實是開飯了~)
有沒有機會能先睹為快呢~
假設, 這部分能做到上述所說。
但還是有別的問題。
比如參數綁定(boost.bind), 在其他范疇里叫partial apply。
其他語言要實現這個簡直太容易了, 語言直接支持, 不需要一個額外的庫。
也不需要關心被bind的參數的生命周期問題。
比如匿名函數, boost.lambda應該也是有不少限制的, C++0x目前也不算太成熟 —— 還有這么多人用VC6呢…… 能讓他們進化到VC8就很感謝了, VC10感覺是奢望。
還有你上面提到"給handler一個名字, 以方便從handler們中刪除" —— 這完全就是動態類型語言常用的方式嘛……
比如lua:
handlers = {}
添加:
handlers[name] = handler
調用:
for _,v in pairs(handlers) do v( ... ) end
刪除:
handlers[name] = nil
還有樓主提到的typelist, 其實是無法展開為參數列表的。
這功能在動態類型語言里也太容易了……
最簡單的元編程方式, 就是產生所需代碼的字符串, 然后加載之……
總之呢, 當需要靈活性時, C++就缺這缺那的, 什么都要自己去造……
造的時候, 又有各種問題。
造的時候肯定是很有成就感的, 編程的樂趣啊!
但就我個人而言, 已經懶惰了……
re: C++ 下 Function 對象的實現(上) OwnWaterloo 2011-01-18 18:37
@cexer
上面所說的"一個類只需要產生一個instance"是非常極端的情況。
實際上是否真的會產生這樣的情況?
比如那個動態產生button的問題。
如果依然遵守靜態類型的方式, 既然"預見" 會產生多個button, 是否可以先在on_command里留下stub, 然后把on_command這部分動態化。
每個button被按下的行為不同, 但這些行為是否依然是"可預見"的?
是否依然可以將它們歸入到同一類型中, 比如使用類多態機制?
"A完全動態" 的方案給我的感覺是: 這已經不是在用C++, 而是在C++中實現一個微型動態類型系統, 然后用動態類型的方式編程。
如果是我個人作出選擇的話, 當需要這種靈活性時, 直接把C++丟了, 選其他動態類型語言來編程-_-
re: C++ 下 Function 對象的實現(上) OwnWaterloo 2011-01-18 18:27
@cexer
感謝感謝~ 果然是經驗豐富的大神。
我想說的就是對象模型不同導致的"空間和效率"上的差異。
C++ 其實不是"面向對象"語言, 而是"面向類" 語言。
真正的面向對象語言, 每個instance都是相互獨立的。
而C++,每一個type的所屬instance共享一部分行為。
C++其實就是將"可能擁有一組相同行為"的instance們, 歸屬到同一個類里,
共享許多信息, 并提高空間與時間效率。
但是, 當instance們的行為復雜(靈活)到一定層次時, 極端情況, 就是一個class, 只需要一個instance。
這時候, 如果依然遵守靜態類型的桎梏, 為每種行為組合編寫一個類, 就會非常繁瑣, 遠不如動態類型語言來得方便。
re: C++ 下 Function 對象的實現(上) OwnWaterloo 2011-01-18 02:17
借寶地請教一下~ 對于handler, 是否需要如此的動態?
A. 完全動態
比如, 一個具體的 window 類。
window w; // 具體的一個類
w.add_handler( ON_CREATE, my_on_create, ... ); // 動態的添加一些handler。
具體語法不重要, w.add_handler<ON_CREATE>(my_on_create, ...);
關鍵點是, window是一個具體類, 動態的(運行時而非編譯時)添加一些handler。
if (some_condition)
/*run time*/w.add_handler( ON_CREATE, my_on_create, ... );
B. 完全靜態
與之相對的, 是編譯時就決定一個類型, 比如 my_window。
然后讓它處理 ON_CREATE。 如何讓WndProc分派到這個handler同樣不是重點。
重點是my_window的每個instance肯定都會處理這個event, 沒有例外。
C. 兩者結合, 動態部分自己實現。
兩者的折中可能是這樣:
1. 依然是一個具體的, 編譯時決定處理哪些event的window類, 比如叫y_window
2. 在設計y_window時, 認為有"部分"(而非window那樣的全部)行為需要在運行時定制
3. 在event中留一些stub, 用于運行時添加。
比如 y_window::on_create( param ){
/*同樣, wndproc 如何分派到這里不重要*/
/**/for (it=this->on_create_handlers.begin(); it!=this->on_create_handlers.end(); ++it) *it(param);
}
y_window::add_on_create( f , ... ) {
/**/this->on_create_handlers.push_back(f, ... );
}
如上, 需要A那種靈活性么? 缺之不可?
因為我自己確實沒寫過幾個gui程序, "作為一個庫的用戶", 沒有足夠的這方面的使用經驗。
re: C++ 下 Function 對象的實現(上) OwnWaterloo 2011-01-18 02:01
typelist 不給力的, 它沒辦法展開為一個參數列表。
最終還是需要boost.pp 那樣的東西。
我記得cnblogs有一個功能, 只許注冊用戶評論。
如果cppblog也有這個功能, 就打開唄。
cppblog上的注冊用戶素質都還不錯。
re: C++關鍵字mutable的思考 OwnWaterloo 2010-10-30 11:50
邏輯上是const, 但又必須修改成員。 比如緩式求值什么的。
造輪子是可以的。
同時也建議嘗試一下其他語言, 比如python或者perl。
有趣的東西很多, 但不是什么都適合用C++去寫。
比如metablog api, python也就分分鐘的事情。
總之嘛, 解決這些"程序員日常雜活", 學點C++之外的語言是很方便的。
re: 深入解析c++靜態聯編和類的成員函數調用 OwnWaterloo 2010-10-27 11:01
@天下
能詳細說說是哪一章節, 以及哪一版本嗎?
中文版至少有3個版本, 侯捷的簡體與繁體、 還有另一個人翻譯的簡體。
再次感謝~
@溪流
我最開始是聽一個學弟在論壇上這么說, 以為是他自己造的一個詞。
后來偶爾也有文章出現這樣的詞。
今個兒終于逮到機會問問。
是哪本大學教科書啊?
re: 學習下 WTL 的 thunk OwnWaterloo 2010-10-26 19:35
@溪流
>> 路過同學的例子確實也指出了一個用bind拐個彎設置到原始C函數指針上去的方法
bind生成的可調用體 —— 一個instance —— 依然需要通過某種方式傳遞到callback中。
而現在的問題就是如何將這個context傳遞進去。
所以我一直說, bind根本就不是解決這個問題的方法, 它本身需要這個問題解決之后才能使用。
re: 學習下 WTL 的 thunk OwnWaterloo 2010-10-26 19:30
@路過
最煩這種瞅住機會就迫不及待的秀一下自己似是而非的理解, 離題萬里。
浮躁!
re: 學習下 WTL 的 thunk OwnWaterloo 2010-10-26 19:27
>>照這種方法法不能推導出wndproc的用法?
>>還是“如果”,有意義?
你有點起碼的邏輯分析能力嗎?
說threadproc是幫助你理解這兩者的不同, 既然不同, 那就是不可導出的。
既然好心被當作驢肝肺, 那別什么"如果"了, 你自己動手去導出wndproc試試。
然后, 摸著自己的良心說: wndproc缺少的參數是靠什么傳入的。
是bind嗎? 是function嗎? 是華麗的語法嗎?
還是我在前面提到的那些東西: table, cbExtra, GWL_USERDATA, Set/GetProp, thunk?
re: 學習下 WTL 的 thunk OwnWaterloo 2010-10-26 19:15
@路過
lz的標題是 WTL thunk。
thunk你懂嗎? thunk解決的是華麗的語法, 還是缺少的context參數?
re: 深入解析c++靜態聯編和類的成員函數調用 OwnWaterloo 2010-10-26 18:26
請教一下, "靜態聯編"和"動態聯編"這兩個術語的出處在哪?
re: 學習下 WTL 的 thunk OwnWaterloo 2010-10-26 00:10
@路過
作者討論的是“如何開啟一個線程”嗎?
不, 作者討論的是如何給WndProc塞入一個context。
哪誰在討論ThreadProc?
是你, 將討論從WndProc轉移到ThreadProc。
我怕你不懂WndProc和ThreadProc究竟有什么重大區別,
以及, 也許你不熟悉WndProc,
所以想就近從你熟悉的ThreadProc中給你一點啟發 —— 就是移除ThreadProc的context參數。
設想一下ThreadProc如果沒有void*參數, 編程會是個什么樣子, api有多難擴展。
以及, 問題的關鍵究竟是什么?
你是不明白啊, 還是不明白啊, 還是不明白?
多說一句, GWL_USERDATA我在上面已經提到過, 是誰回帖不看貼的?
再多提醒一句, GWL_USERDATA并不是你想象的那么簡單。
究竟是什么, 請繼續看我在樓上的回復。
re: 學習下 WTL 的 thunk OwnWaterloo 2010-10-25 23:09
@路過
喔?。?好華麗, 好耀眼哦!
class, thread, callable, run什么的, 我看不懂也!
我就問一句, 還望賜教賜教啊~
如果CreateThread使用的線程函數的簽名是這個樣子:
unsigned threadproc(void); // 注意, 是void, 而不是void*
你用上面那些華麗的東西給我看看?
全局變量什么的也丑的, 也不許用哦!
WndProc就是這樣一個場景 —— 回調的簽名沒有void* context。
您, 明白了嗎?
re: 學習下 WTL 的 thunk OwnWaterloo 2010-10-25 09:33
@waiting4you
有。
Windows支持的體系結構里, ATL的stdthunk都有實現。
編譯switch也不用自己操心, 都寫好了的。
re: 學習下 WTL 的 thunk OwnWaterloo 2010-10-24 22:10
@溪流
因為用的人少啊
re: 學習下 WTL 的 thunk OwnWaterloo 2010-10-24 21:53
@陳梓瀚(vczh)
這問題用bind解決不了。
bind生成的對象, 需要template配合。
比如: for_each(begin, end, bind( ... ) );
for_each是一個函數模板。
而WndProc必須是一個函數指針。
lpWndProc = bind( ... ); 是不行的。
re: 學習下 WTL 的 thunk OwnWaterloo 2010-10-24 18:13
@溪流
WTL我不熟, 深入研究的也就是和thunk相關的東西……
給人的感覺是模板使用過度。
比如, 居然用一個模板參數去傳遞兩個窗口風格參數。
感覺是C++的混沌年代, 大家都還不知道如何合理使用模板的情況下, 產生的東西……
所以也不愿意多看……
想研究gui的話, cppblog有個 cexer, 看過很多gui的框架, 可以向他咨詢。
re: 學習下 WTL 的 thunk OwnWaterloo 2010-10-24 18:08
@溪流
沒什么好慚愧的呀……
實驗、 玩具代碼這很正常。 為了突出重點(機器代碼的構造)而非內存管理。
造輪子也是很好的練習。
只是, 輪子在投入正規使用前, 一定要謹慎。
玩具代碼中忽略的非重點, 恰恰可能占了很多代碼, 繁瑣、 無趣、 bug叢生……
如果真有恒心把這些問題處理好, 再和現有的輪子客觀的比較權衡之后, 再考慮使用。
因為看過許多把玩具代碼 —— 而且是一些相當沒有技術含量, 僅僅是滿足個人審美觀而已 —— 的代碼放入實際工程中, 還很自鳴得意的……
慘不忍睹啊……
re: 學習下 WTL 的 thunk OwnWaterloo 2010-10-24 17:43
virtualalloc不是這樣用的啊, 同學……
virtualalloc的粒度很大(保留按64k, 提交按頁)。
也就是說, 如果直接用virtualalloc, 每個window instance, 要占用64k地址空間, 并使用至少4k內存。
ATL不同版本處理這個問題好像采取的策略不同。
有你提到的使用virtualalloc分配, 然后再劃分。
還有直接使用HeapCreate創建一個分配可執行內存的win32 heap。
這些技術很炫, 研究起來也很有成就感。
玩具代碼當然可以隨便用, 但成熟代碼盡可能選取成熟的技術。
比如全局table。它的效率問題真的無法忍受嗎? 或者全局帶來的其他問題(多線程相關)很要緊嗎?
如果窗口類是自己注冊的, 可以用cbExtra。
如果不是, 而且GWL_USERDATA是開放的(對話框和MDI是保留給自己用的), 那可以用GWL_USERDATA。
還可以用Set/GetWindowProp。
如果thunk機器相關的缺陷不要緊, 而且上述的這些成熟的方案都不合適, 也不一定非要自己寫內存池, HeapCreate在windows上總是可用的。
re: 問一個語法問題 OwnWaterloo 2010-10-15 18:56
@溪流
哦, 對, 你這么一說想起來了。
確實有歧義。 問題差不多: 一個隱式轉換到T*, 一個[]操作符。
o[x] 究竟是 o.operator T*()[x] 還是 o.operator[](x)。
看這里:
http://www.glenmccl.com/ansi_022.htm但究竟是怎么規定的, 忘了…………………………
re: 問一個語法問題 OwnWaterloo 2010-10-15 15:32
歧義在哪?
re: Visual Studio 歷史簡介(轉) OwnWaterloo 2010-08-21 14:11
@溪流
1. 具體我也不清楚……
不過這應該都有據可查……
2.
String& operate=(String const& other)
{
size_t len = strlen(other.p);
char* p = new char[len+1];
strcpy(p, other.p); // 風險在哪?
delete [] this->p;
this->p = p;
}
int i = 0;
scanf("%d", &i); // 風險在哪?
char buf[numeric_limits<int>::digit10+2];
sprintf(buf, "%d", i); // 風險在哪?
上面的警告還可以通過一個宏定義 _CRT_SECURE_NO_DEPRECATE全部干掉。
std::copy就更搞笑了, 要抑制警告, 必須#pragma…… 先push, 再disable, 再pop……
非常非常干擾源文件的表達。
如果不在源文件里, 而是在構建腳本里, 那更復雜。
.vcproject手工改嗎? cmake如何加入自定義編譯選項?
std::copy(src.begin(), src.end(), back_inserter(dst) ); // 風險在哪?
還有那個/Wp64。
VS2005的這些新東西, 全他媽是傻逼設計。
re: Visual Studio 歷史簡介(轉) OwnWaterloo 2010-08-21 08:56
@溪流
VC6情有可原?
好吧, 那VC8加入的所謂的security crt怎么解釋?
硬生生的將scanf, std::copy等函數列為廢棄?
硬生生的將open, read的函數列為廢棄, 而且是以莫名其妙的理由?
非不能, 乃不愿也。
re: 一個大整數類的實現 OwnWaterloo 2010-08-21 08:26
"任意精度的整數類 *模板* " —— 這事情我也干過……
現在如果有必要再造輪子, 感覺應該沒有模板的必要……
re: 關于C++之“復雜” OwnWaterloo 2010-07-08 19:29
@陳梓瀚(vczh)
控制for中的變量的scope?
還是禁用異常?
還有其他的么?
re: 關于C++之“復雜” OwnWaterloo 2010-07-07 21:53
@陳梓瀚(vczh)
如果C++再提供一個"特性": 可以禁用某些方面的另外的特性。
團隊合作時會不會好一些?
比如看異常不爽的團隊, 直接在構建腳本里, 通過編譯選項把異常的使用給禁了。
看xxx不爽的, 也可以。。。
re: 關于C++之“復雜” OwnWaterloo 2010-07-07 19:26
@陳梓瀚(vczh)
討論, review什么的, 有一些用處, 但不能全防住。
特別是"團隊換人"的時候。
這些討論不一定會被良好的記錄。
新成員可能就亂來了。
如果是團隊大換血, 可能新的團隊就會覺得現有代碼是坨屎。
>> 至于說選擇多的東西交給一群沒經驗的人是會出問題的,那這不就證明他們要是能力不足或者不想學這么多東西,就應該去用C#和Java而不應該用C++嗎。
沒有經驗、 能力不足、 不思進取、 混口飯吃的, 恰恰占大多數。
所以, C++也只是少數人手中的利刃, 不是誰都玩得轉的。
一部分玩不轉的人, 就把原因歸咎到C++過于復雜。
推卸責任是很常見的心理。
re: 關于C++之“復雜” OwnWaterloo 2010-07-07 16:55
我覺得只是復雜, 問題還不大。
C++的問題出在給出的特性分了岔。
從留言中就已經可以看出有(曾經)崇尚OO的,和不主張OO的兩派。
當團隊中人數再增加時, 肯定還會出現更多派系。
如果沒能很好的控制, 就很難和諧, 造成四不像的設計。
相比而言, C和java都沒這么容易分岔。
尤其是java, 團隊中基本不會出現不兼容的設計, 因為沒有什么其他的好的選擇。
re: 2D場景節點實現(空間關系) OwnWaterloo 2010-07-07 00:45
評論通知啊……
通知啊……
啊……
……
re: [C++]內存管理(1) OwnWaterloo 2010-07-07 00:08
@volnet
詳細設計部分在cppblog上調整過樣式吧?
我見過一個白色的頁面, 過段時間刷新后, 就變黃色了。
很用心~
re: [C++]內存管理(1) OwnWaterloo 2010-07-06 23:29
請教一下: 這個排版是怎么做的? live writter?
re: C++的流設計很糟糕 OwnWaterloo 2010-07-06 14:16
鮮明的對比:
學會了errno就學不會exception。
學會了prints就學不會streams。
學會了C就學不會C++。
。。。
學會了errno繼續學exception。
學會了printfs繼續學streams。
學會了C繼續學C++。
。。。
re: size_t的倒序遍歷問題 OwnWaterloo 2010-07-01 17:33
for (size_t i=n; i-- /*!=0*/; )
...
re: C++實用技巧(二) OwnWaterloo 2010-06-24 14:12
re: C++實用技巧(二) OwnWaterloo 2010-06-24 11:25
@陳梓瀚(vczh)
無論是C還是C++, 說的都是"編譯時可求出0值的常數是空指針常量"。
可以將空指針賦值給任意指針類型的變量。
但并不保證賦值之后指針變量的二進制表示也是全0。
從語法上講:
void* p = 0;
void* p=(void*)(int)0;
都是對的, 就像:
float f = 0;
float f = (float)(int)0;
而通常f的二進制表示并不是全0。
這是因為編譯器是能看到這里的轉型動作, 并加入適當的操作。
但這樣寫就是沒有保證的:
void* p;
memset(&p, 0, sizeof p);
memset函數中已經不知道p的類型, 只能將p當作byte 數組。
就沒有機會為指針類型作適當的調整。
再舉個例子:
class A {};
class B {};
class C : public A, public B {};
C c;
C* pc = &c;
A* pa = pc;
B* pb = pc;
assert( pc==pa && pc==pb);
因為編譯器知道pc,pa,pb的類型。
所以無論是賦值還是比較, 都會插入適當的操作。
而如果使用memset或者memcmp, 就掛了。
最后, 標準中有句話, 在calloc的腳注里。
The calloc function allocates space for an array
of nmemb objects, each of whose size is size.
The space is initialized to all bits zero.
Note that this need not be the same as the representation
of floating-point zero or a null pointer constant.